x
x
100.24.46.*

最新文章 Latest Blogs

2019-01-14 YHSPY 共  1185 个不明生物围观

《重新定义团队:谷歌如何工作》读书笔记(5/20)。最近花了一些时间来读《重新定义团队:谷歌如何工作》这本书,在这里记录一下书中提出的关键点。怎样才能发挥团队的最大效能,同时让团队中的成员保持高涨的激情,这些都是在团队管理中会经常遇到的问题。

2019-01-08 YHSPY 共  24 个不明生物围观

《阿米巴经营》读书笔记(4/20)。这里记录了一些在读书过程中提炼出我觉得有价值的观点,仅供参考。

2019-01-07 YHSPY 共  55 个不明生物围观

《零售的哲学》读书笔记(3/20)。这里记录了一些在读书过程中提炼出我觉得有价值的观点,仅供参考。读下来铃木先生以其自身的经历为线索介绍了7-11这40年来发展的重点历程。整个创业经验总结出一句话就是“以人为本,学会改变”。相信这样的态度可以让冰冷的“商业”与消费者走的更近,从而获得用户的信任和支持。但这样的创业信条是否适用于处在发展中国家的我们呢?这还是个疑问,持保留态度。

2019-01-05 YHSPY 共  47 个不明生物围观

《增长黑客:创业公司的用户与收入增长秘籍》读书笔记(2/20)。这里记录了一些在读书过程中提炼出我觉得有价值的观点,仅供参考。与其说本书是介绍“增长黑客”不如说是以“增长黑客”为视角来介绍针对创业中几个关键节点(AARRR)的案例和分析。前半部分干货还是有一些的,后半部分稍显不足。书中的案例主观分析只能用做参考,有一些营销技巧和产品准则倒是值得学习和借鉴。

2018-11-29 YHSPY 共  95 个不明生物围观

Git是一款免费、开源的分布式版本控制系统,相比于之前的CVS、SVN等版本控制系统,Git的优势大大凸显。Git是分布式的版本控制系统,相比之前的集中式系统,分布式版本控制系统的安全性要高很多。因为每个人电脑里都有完整的版本库,使得整个版本库不会轻易的丢失。

2018-08-29 YHSPY 共  275 个不明生物围观

鉴于网站的博客发布系统过于老旧,现将内容提交系统重构并增加支持对 Markdown 格式的内容转换。该文章为测试内容,用于测试网站对 MD 转换文本的支持效果。两套渲染模式将兼容存在,网站并无计划进行技术上的整体重构。

2018-01-08 YHSPY 共  1450 个不明生物围观

今天听了银奎老师分享的最近火热技术圈的 Meltdown 漏洞的基本原理,才知道原来底层系统的世界是如此的丰富多彩。Meltdown 漏洞的 POC 实现基于了一种名为 “Flush & Reload” 的黑客攻击技术,这项技术的基本原理是利用 Memory 和 Cache 之间的关系,同时利用统计学的置信程度来筛选关键信息的。

2017-12-24 YHSPY 共  943 个不明生物围观

最近在读《重新定义团队:谷歌如何工作》,学习谷歌在技术团队管理上的一些思考和方式。同时上周也刚刚从杭州 D2 前端技术论坛回来。在会上,来在360和阿里的技术主管也分享了各自在团队管理上的多年经验,特此整理一下会上和自己对技术团队管理的一些思考。

2017-12-17 YHSPY 共  881 个不明生物围观

一般来说,一项新技术是否会随着时代的推进而被快速地迭代和发展,要看这项技术所应用在的实际业务场景中是否有相应的技术需求,毕竟没有任何技术是会被凭空创造出来的。技术决定了业务需求的多样性,而业务需求的多样性又推动着技术不断向前发展,两者相辅相成最终才能推动行业整体的发展和进步。

2017-11-12 YHSPY 共  773 个不明生物围观

如今,软件通常会作为一种服务来交付,它们被称为网络应用程序,或软件即服务(SaaS)。12-Factor 为构建如下的 SaaS 应用提供了方法论。这套理论适用于任意语言和后端服务(数据库、消息队列、缓存等)开发的应用程序。

    文章日期索引 Date Index

    文章类别索引 Type Index

    文章主体 Detail

    WebAssembly 尝试研究报告(一)

    自 WebAssembly 技术从 2016 年出现开始,便一直受到各方的关注。从宏观上来看,使用该技术可以通过把 Web 端的复杂运算放在 C/C++ 中执行,并且使 JS  可以通过 WebAssembly 提供的接口与 C/C++  进行交互,进而达到提升 Web 应用程序性能的目的。该技术的 MVP 版本刚刚发布不久,DOM 方面的功能实现还有待进一步完善。

    为了迎接 WebAssembly 的怀抱,Chrome 也开始不再支持 PNaCI,开始全面支持 WebAssembly。毕竟 PNaCI 曾经受到了 Mozilla 的批评,公开指责其违背了“坚持开放和接受 Web 标准”的原则。现在 WebAssembly 已经成为新的 Web 标准,旨在为了改进 JS 的性能作出贡献。

    一、开发环境的搭建

    1、可以通过 WebAssembly 的官方开发者文档基于 Emscripten 工具链进行开发:

    2、可以通过 WasmFiddle 进行在线的实时开发和运行;

    3、独立安装 cmake、gcc、clang、llvm、s2wasm、wast2wasm 等编译器和环境;

    二、开发工具

    对于非线上的开发模式,Windows 平台需要安装 Visual Studio,Mac 平台需要安装 XCode。线上模式只需要一个文本编辑器即可。

    三、发展历史

    JS 引擎的发展经历了遍历 AST、字节码解释器等“原始”阶段,由于需要将每条源代码“翻译”成相应的机器码并执行,同时引擎不会保存“翻译”后的机器码,使得解释执行的速度很慢。接下来 Google 发布了 V8 引擎,由于采用了 JIT 技术,在执行时将 JavaScript 代码编译成更高效的机器代码并保存,下次执行同一代码段时无需再次编译,使得 JavaScript 获得了几十倍的性能提升。但是由于 JS 本身的弱类型,导致引擎在解析同一段代码时会有不同的结果,因此大量的引擎资源被浪费在数据类型的判断上。微软开发的 TypeScript 采用了强类型的方式扩展了 JS 的语法特性,从语言层面解决了引擎在判断变量类型上的资源浪费问题。

    我们不想去创造一门新的强类型语言来代替 JS,那么有没有办法把现有的静态强类型语言“翻译”到 JS 呢?最早的尝试可以追溯到 95 年的 NPAPI 项目,但更为人所知的应该当属 13 年发布的 Asm.js。Asm.js 是一种 JS 的中间语言,其本质也是基于 JS 的语法,只不过是被特别优化过的。我们可以通过 Emscripten 将 C/C++ 代码传入 LLVM,再将 LLVM 产生的字节码编译成 Asm.js 代码,由于 Asm.js 本身的优化机制限制,导致 Asm.js 本质上只能处理和优化数值类型。所有的 Asm.js 代码都已经被高度优化,所有的变量类型明确,所有的外部数据都在堆中进行存储和优化,甚至可以直接将 Asm.js 编译成底层的汇编代码而不需要特殊的处理。

    这就可以了吗?看上去不错,通过 Asm.js 我们可以直接用 C/C++ 来编写高性能的 Web 应用,但其缺点也是明显的:编译后的 JS 文件过大,跨浏览器支持不佳等。WebAssembly 为了解决这个问题而诞生了。Wasm 不是一种新的编程语言,而是一种新的格式,这个格式适合将 C/C++ 程序编译到 Web 上来运行,同时又满足了平台无关、高效、轻量等特性。Wasm 可以直接被 JS 引擎加载和执行,省去了从 JS 到 Bytecode,从 Bytecode 到机器码的转换时间,因此十分高效。Wasm 的文本格式 Wast 包含了一个基于 S 表达式的 AST 描述文本,在这个文件中我们可以清楚的看到这个 Wasm 模块的导出函数内存分配的情况。WebAssembly 的二进制模块格式 Wasm 可以直接通过 JS 引擎提供的 WebAssembly 接口进行调用。

    四、编译流程

    从 C/C++ 编译到 JS 的流程大致相同,如果开发流程基于 Em​scripten 工具链,整个编译环境的大致流程如下图(转载):

    Emcc 是 Emscripten 的编译器前端,其本身和 GCC 十分相似。Emcc 使用 Clang 将 C/C++ 代码转换为 LLVM(源自于底层虚拟机 Low Level Virtual Machine)字节码,使用 Fastcomp(Emscripten 的编译器核心,一个 LLVM 后端)把字节码编译成 JavaScript 可直接在浏览器中运行。无论是从 Asm.js 到 WebAssembly 二进制代码还是从 Wast 到 Wasm,都可以很方便的通过现有的工具链进行编译和转换。

    五、本地实验

    我们分别通过使用原生 JS 的排序方法和基于 C/C++ 实现的 Wasm 版本的排序方法来对比两种实现的性能差别。

    实验流程:实验数据采用随机生成的含有 100 个随机数的数组,通过比较对该数组进行一百万次排序的时间来比较两种方式的性能差异。

    实验细节:JS 采用 Array.prototype.sort 进行排序,Wasm 采用 C/C++ 实现的快排方法进行排序。

    1、JS 端排序测试

    
    console.time("JS-Native");
    for (let j = 0; j < 1000000; j++) {
      let arr = [];
      for (let i = 0; i < 100; i++) { 
        arr.push(Math.round(Math.random() * 100));
      }
      arr.sort((a, b) => {
        return a - b;
      })
    }
    console.timeEnd('JS-Native');
    

    上述代码为 JS 端的数组排序测试代码。下面的 C/C++ 数组排序我们采用快排的思路来编写。基于 WebAssembly 的开发主要分为两个部分,第一部分为 C/C++ 部分的主要业务处理逻辑,同时需要设置一些需要在 JS 层面调用的“预置接口”。第二部分是在 JS 层面进行 Wasm 的模块对接,同时需要填充内存或者预置函数的逻辑,填充数据集的操作。

    2、Wasm 端排序测试

    
    // 定义数组大小
    #define N 100
    
    // 预置函数,暴露给 JS 进行处理
    void print(int* offset, int length);
    
    int array[N];
    // 返回数组在内存中的偏移地址
    int* getArrayOffset() {
      return array;
    }
    
    void swap (int *a, int *b) {  
      int temp;  
    
      temp = *a;  
      *a = *b;  
      *b = temp;  
    
      return;  
    }  
    // 快排实现  
    void quicksort(int array[], int maxlen, int begin, int end) {  
      int i, j;  
    
      if(begin < end) {  
        i = begin + 1;
        j = end;      
            
        while(i < j){  
          if(array[i] > array[begin]) {  
            swap(&array[i], &array[j]); 
            j--;  
          } else {  
            i++;   
          } 
        }  
    
        if(array[i] >= array[begin]) {  
          i--;  
        }  
    
        swap(&array[begin], &array[i]);  
          
        quicksort(array, maxlen, begin, i);  
        quicksort(array, maxlen, j, end);  
      }  
    }  
    
    void test () {
      quicksort(array, N, 0, N - 1);
      // print(array, N);
    }
    

    上面给出的 C/C++ 端的处理函数处理了几件事情:1、暴露了一个方法外壳给 JS 来处理;2、提供一个函数用于获得数组在内存中的偏移地址;3、核心业务处理逻辑的函数;4、一个主函数用于在 JS 的中调用;接下来处理 JS 端的 Wasm 接口和数据的填充。

    
    // 将 JS 生成的数组数据填充到指定的内存中;
    function importArrayToBuffer (memory, array, offset) {
      const importBuffer = new Uint32Array(memory.buffer, offset, array.lenth);
      for (let i = 0; i < array.length; i++) {
        importBuffer[i] = array[i];
      }
    }
    
    let memory;
    // 通过浏览器提供的 WebAssembly 接口来加载一个 Wasm 模块;
    WebAssembly.compile(wasmCode).then(module => WebAssembly.instantiate(module, {
      env: {
        // 填充预置函数的主体;
        print (offset, len) {
          let strBuffer = new Uint32Array(memory.buffer, offset, len);
          console.log(strBuffer);
        }
      }
    })).then(instance => {
      let exports = instance.exports;
      memory = exports.memory;
      console.time("WASM");
      // 开始测试
      for (let j = 0; j < 1000000; j++) {
        let arr = [];
        for (let i = 0; i < 100; i++) { 
          arr.push(Math.round(Math.random() * 100));
        }
        // console.log("[Generated Array] ", arr);
        // 填充数据到指定内存段
        importArrayToBuffer(memory, arr, exports.getArrayOffset());
        // 调用 C/C++ 暴露的逻辑处理函数;
        exports.test();
      }
      console.timeEnd('WASM');
    });
    
    

    3、JS 端快排测试

    为了增强对照实验的准确性,我们又追加了纯 JS 实现的快排来作为第三种对照组实验。实验代码如下:

    
    // 快排实现  
    function quicksort(array, maxlen, begin, end) {  
      let i, j;  
      
      if(begin < end) {  
        i = begin + 1;
        j = end;      
            
        while(i < j){  
          if(array[i] > array[begin]) {  
            let temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        
            j--;  
          } else {  
            i++;   
          } 
        }  
    
        if(array[i] >= array[begin]) {  
          i--;  
        }  
      
        let temp = array[begin];
        array[begin] = array[i];
        array[i] = temp;
          
        quicksort(array, maxlen, begin, i);  
        quicksort(array, maxlen, j, end);  
      }  
    }  
    
    function main () {
      console.time("JS-Quick");
      for (let j = 0; j < 1000000; j++) {
        let array = [];
        for (let i = 0; i < 100; i++) { 
          array.push(Math.round(Math.random() * 100));
        }
        quicksort(array, array.length, 0, array.length - 1);
      }
      console.timeEnd('JS-Quick');
    }
    
    

    一百万次 对随机生成的含有 100个数字 的数组进行排序所花费的时间:[JS-Native: 11308.10498046875ms][WASM: 7366.18310546875ms][JS-QUICK: 38611.242919921875ms],WebAssembly 以十分明显的优势胜出。总结的来看,从 JS 向固定的内存地址段进行数据填充的过程其实可以有很大的优化空间,比如将业务需要进行处理的数据一次性全部写入内存来代替分次的写入。C/C++ 方面可以对数据结构进行更加灵活的处理,比如在某些情况下使用链表等数据结构来大幅度改善程序等运行效率等。

    为了更加精准的对 WASM 进行性能评估,我们又追加了不同数组大小的实验样本作为参照,具体评估结果如下图所示(Mac OS, Chrome Version 58.0.3029.110 (64-bit)):

    发布时间 : 2017-06-09 11:55:00 作者 : YHSPY 类别 : WEB前端 Miscellaneous
    查看评论
    点击已评论用户的用户名可以@他

    一语浏览 Detail

    语言 C/C++
    
    // 智能指针的错误用法;
    shared_ptr<int> p(new int(42));
    int *q = p.get();
    {
      shared_ptr<int> p(q);
    }
    int foo = *p // 未定义行为,动态内存已被释放;
    
    
    服务器 Linux

    修改用户所属组:

    sudo usermod -G <group> <username>

    语言 C/C++

    inline functions

    优点:

    1、通过避免函数调用开销来加速程序。

    2、当函数调用发生时,它可以节省堆栈上变量调用的开销。

    3、它节省了函数返回的开销。

    4、它利用指令缓存增加了引用的局部性。

    5、通过将其标记为内联,可以将函数定义放在头文件中。

    缺点:

    1、由于代码扩展,它增加了可执行文件的大小。

    2、C++ 内联在编译时解决。这意味着如果更改内联函数的代码,则需要使用它重新编译所有代码以确保它将更新

    3、在头文件中使用时,会使头文件体积增大,进而应用体积增大。

    4、在某些嵌入式系统中无效。因为存储器限制,编译器不希望增大可执行文件大小。

    何时使用:

    1、需要性能时使用内联函数。

    2、在宏上使用内联函数。

    3、喜欢在类外部使用带有函数定义的内联关键字来隐藏实现细节。

    关键点:

    1、是否内联完全取决于编译器的判断。

    2、内联基于编译器控制,这与宏完全不同:宏将被强制内联,将污染所有命名空间和代码,将不容易调试。

    3、默认情况下,在类中声明和定义的所有成员函数都是内联的。所以不需要明确指定。

    4、虚函数不应该是被内联的。有时候,当编译器可以确切地知道对象的类型时,甚至虚函数也会被内联,因为编译器确切地知道了对象的类型。

    5、模板方法并不总是内联的。

    语言 C/C++
    
    // 拷贝构造函数与赋值运算符重载函数;
    #include 
    
    using namespace std;
    
    struct T {
        int x;
    
        T() = default;
    
        T (int x) : x(x) {};
    
        T (const T& t) {
            this->x = t.x;
            cout << "Copy Constructors: " << this->x << endl;
        }
    
        T& operator=(T& t) {
            if (this != &t) {
                this->x = t.x;
                cout << "Overload Function: " << this->x << endl;
            }
            return *this;
        }
    };
    
    int main (int argc, char **argv) {
        T x(10), t3;
        T* t = new T(20);
    
        /*************************/
        // Copy Constructors: 10 //
        /*************************/
        T t1(x); 
        T t2 = x;
    
        /*************************/
        // Overload Function: 10 //
        /*************************/
        t3 = x; 
        
        delete(t);
        return 0;
    }
    
    
    语言 C/C++

    dynamic_cast 可以用于沿继承层级向上、向下及侧向转换到类的指针和引用。但在确保待转换指针的子类型时,可以使用 static_cast 来进行,以避免检查时的开销(可能不安全,但高效)。

    其他 Others

    JWT(JSON WEB TOKEN)

    可用作分布式系统的单点登录验证系统(SSO)。由于 Token 中的 Signature 部分是由前两个字段和一个密钥一起进行加密后得出来的,因此前端无法擅自修改 Token 中的信息,得以保证信息的获取不会被滥用。同时由于 JWT 的 “self-contained“ 特性,原始 Session 中的信息被全部放到了 Token 中,后端不需要存储任何信息,保证了服务的无状态化,提高了可扩展性。

    数据结构:

    交互模式:

    前端 Javascript

    this 实例:

    1、非 ES5 严格模式下,函数调用的默认 this 指向 window,严格模式下指向 undefined

    2、对象中函数的 this 指向调用方;

    
    var person = {  
      name: "Jason",
      say: function(thing) {
        console.log(this.name + " says hello " + thing);
      }
    }
    person.say("world"); // "Jason says hello world"
    
    var iSay = person.say;
    iSay("world"); // "undefined says hello world"
    

    3、使用 bind 来固化 this

    
    var boundSay = person.say.bind(person);  
    boundSay("world") // "Jason says hello world"
    
    前端工程化

    GitFlow 工作流:

    1、主分支只用于 Hotfix 和发布后的发布分支合并;

    2、专门的 Develop 分支用于 Feature 分支的合并;

    3、从 Develop 分支拷贝的发布分支,发布分支只有 Hotfix 合并,发布后合并回主分支和 Develop 分支;

    4、Hotfix 分支合并回主分支和 Develop 分支;

    5、每一次到主分支的合并都需要打 Tag 以便追踪记录;

    前端 HTTP

    HTTPS 通信流程:

    前端 HTTP

    浏览器常用缓存策略流程:

    代码库 Code Depot

    React 实例 - 单一数据源原则
    
    const scaleNames = {
      c: 'Celsius',
      f: 'Fahrenheit'
    };
    
    function toCelsius(fahrenheit) {
      return (fahrenheit - 32) * 5 / 9;
    }
    
    function toFahrenheit(celsius) {
      return (celsius * 9 / 5) + 32;
    }
    
    function tryConvert(temperature, convert) {
      const input = parseFloat(temperature);
      if (Number.isNaN(input)) {
        return '';
      }
      const output = convert(input);
      const rounded = Math.round(output * 1000) / 1000;
      return rounded.toString();
    }
    
    function BoilingVerdict(props) {
      if (props.celsius >= 100) {
        return <p>The water would boil.</p>;
      }
      return <p>The water would not boil.</p>;
    }
    
    class TemperatureInput extends React.Component {
      constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
      }
    
      handleChange(e) {
        this.props.onTemperatureChange(e.target.value);
      }
    
      render() {
        const temperature = this.props.temperature;
        const scale = this.props.scale;
        return (
          <fieldset>
            <legend>Enter temperature in {scaleNames[scale]}:</legend>
            <input value={temperature}
                   onChange={this.handleChange} />
          </fieldset>
        );
      }
    }
    
    class Calculator extends React.Component {
      constructor(props) {
        super(props);
        this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
        this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
        this.state = {temperature: '', scale: 'c'};
      }
    
      handleCelsiusChange(temperature) {
        this.setState({scale: 'c', temperature});
      }
    
      handleFahrenheitChange(temperature) {
        this.setState({scale: 'f', temperature});
      }
    
      render() {
        const scale = this.state.scale;
        const temperature = this.state.temperature;
        const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
        const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
    
        return (
          <div>
            <TemperatureInput
              scale="c"
              temperature={celsius}
              onTemperatureChange={this.handleCelsiusChange} />
            <TemperatureInput
              scale="f"
              temperature={fahrenheit}
              onTemperatureChange={this.handleFahrenheitChange} />
            <BoilingVerdict
              celsius={parseFloat(celsius)} />
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <Calculator />,
      document.getElementById('root')
    );
    

    使用方法:浏览器。

    代码说明:完整的 Reactjs 代码片段。

    一个完整的 React 实例
    
    // sub-component
    function ListItem(props) {
      // Correct! There is no need to specify the key here:
      return <li>{props.value}</li>;
    }
    
    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        // Correct! Key should be specified inside the array.
        <ListItem key={number.toString()}
                  value={number} />
    
      );
      return (
        <ul>
          {listItems}
        </ul>
      );
    }
    
    class Clock extends React.Component {
      constructor(props) {
        // 确保 props 能够正确传入;
        super(props);
        // Bind this
        this.handler = this.handler.bind(this);
        this.state = {
          date: new Date(),
          counter: 0,
          showWarning: true
        };
      }
      // 生命周期 Hook 函数;
      componentDidMount() {
        // 不需要在 View 中显示的属性不需要放到 State 中;
        this.timerID = setInterval(
          () => this.tick(),
          1000
        );
      }
    
      componentWillUnmount() {
        clearInterval(this.timerID);
      }
    
      tick() {
        this.setState({
          date: new Date()
        });
      }
      
      handler() {
        this.setState({
          counter: this.state.counter + 1
        });
      }
    
      render() {
        const numbers = [1, 2, 3, 4, 5];
        // JSX 中的 Callback 函数需要在构造函数中绑定 this 指针;
        return (
          <div>
            <NumberList numbers={numbers} />
            <h1 onClick={this.handler}>Hello, {this.props.user.toString()}!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
            <h2>Counter: {this.state.counter}</h2>
            <p>{this.state.counter > 2 && <WarningBanner warn={this.state.counter} />}

    </div> ); } } ReactDOM.render( <Clock user="YHSPY"/>, document.getElementById('root') );

    使用方法:浏览器。

    代码说明:完整的 Reactjs 代码片段。

    Node8 之 Util.promisify 常见用法
    
    var util = require('util')
    
    const wait = (delay, callback) => {
      const id = setInterval(() => {
        const rand = Math.random()
        if (rand > 0.95) {
          callback('Got data successfully!', null)
          clearInterval(id)
        } else if (rand < 0.1) {
          callback(null, 'Sorry, something wrong!') 
          clearInterval(id)
        } else {
          console.log("Waiting...")
        }
      }, Number(delay))
    }
    
    /*
      wait(1000, (data, err) => {
        if (err) {
          throw new Error(err)
        }
        console.log(data)
      })
    */
    
    // Use util.promisify
    util.promisify(wait)(1000).then(data => {
      console.log(data);
    }).catch(err => {
      console.error(err);
    })
    
    // Use async/await instead
    waitAsync = util.promisify(wait)
    let asyncFunc = async () => {
      let result;
      try {
        result = await waitAsync(1000);
      } catch (err) {
        return console.error(err);
      }
      return console.log(result);
    };
    asyncFunc().then(data => {
      // undefined
      console.log(data)
    })
    

    使用方法:Node8 命令行下直接运行。

    代码说明:Node8 新增的函数可以直接 Promise 化一个特定格式的函数,函数的回调函数需要符合 Node 的标准回调函数格式 。

    Leetcode - 169.Majority Element HashMap基础解法
    
    public static int majorityElement(int[] nums) {
        if (nums.length == 0)  // 如果数组长度为0则返回-1
        	return -1;
        
        int arrLen = nums.length;
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0;i < arrLen; i ++) {
        	int currentVal = 0;
        	if (map.containsKey(nums[i]))  // 如果HashMap中存在该值对应的元素则使用该值
        		currentVal = map.get(nums[i]);
    
        	if (currentVal > arrLen / 2) {  // 如果满足条件则返回该元素
        		return nums[i];
        	} else {
        		map.put(nums[i], currentVal + 1);  // 否则对应元素值加一
        	}
        }
        
        return -1;
    }
    

    使用方法:Eclipse新建工程,直接复制到主类里,通过类名静态调用即可。

    代码说明:本段代码为Leetcode题目“169.Majority Element”的实现代码,算法类代码建议先做题,再参考。题目详情请参考文章《Leetcode每日一题 - 169.Majority Element》。

    Leetcode - 219.Contains Duplicate II 窗口检测解法代码片段
    
    public static boolean containsDuplicateOptimizeFurther(int[] nums) {
        Set<Integer> set = new HashSet<Integer>();  
        int start = 0, end = 0;  // 定义窗口的首尾指针
        for(int i = 0; i < nums.length; i++) {   // 开始遍历
            if(!set.contains(nums[i])) {    
                set.add(nums[i]);   
                end++;   // 如果Set中没有此元素则加入,尾指针后移
            } else { 
                return true;   // 有则返回True
            }
            
            if(end - start  > k) {  // 保持首尾指针距离不大于k  
                set.remove(nums[start]);    //如果大于则移除首指针元素
                start++;   // 移除后首指针后移
            }  
        }  
        return false;
    }
    

    使用方法:Eclipse新建工程,直接复制到主类里,通过类名静态调用即可。

    代码说明:本段代码为Leetcode题目“219.Contains Duplicate II”的实现代码,算法类代码建议先做题,再参考。题目详情请参考文章《Leetcode每日一题 - 219.Contains Duplicate II》。