x
x
54.81.196.*

最新文章 Latest Blogs

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

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

2018-01-04 YHSPY 共  812 个不明生物围观

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

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

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

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

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

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

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

2017-11-09 YHSPY 共  582 个不明生物围观

本篇将讨论 Docker 用于构建微服务的相关实践。如何将 Docker 用于生产环境,并且构建一个更复杂的多容器应用?同时利于链接和卷等 Docker 特性来管理 Docker 中的应用,以及 Docker 集群的管理等。

2017-11-07 YHSPY 共  584 个不明生物围观

接着上一篇文章,我们继续深入了解并学习关于 Docker 的基础知识以及相关基于 Docker 实现的典型架构解决方案。Docker 在协调线下/上多环境开发等场景下有其独特的优势。

2017-11-04 YHSPY 共  690 个不明生物围观

Docker 改变了人们日常从开发到部署的工作流方式。不仅如此,Dokcer 在云计算、大数据处理甚至深度学习基础系统架构等方面都有其用武之地和独到之处。Docker 开发的一个目的就是为了加强开发环境与部署环境的一致性。

2017-09-30 YHSPY 共  849 个不明生物围观

随着云计算、深度学习和区块链技术的发展和普及,人们对“运算力”的需求变得越来越迫切。大型公司可以通过横向扩展机房的形式来增加自己的“运算力”,但这种从物理上扩展机器的方式对一些初创的小公司来说是一笔不小得开销负担。

2017-09-07 YHSPY 共  788 个不明生物围观

由于 V8 的 "full-codegen" 编译器在解析 AST 之后生成的机器码十分冗长,因此会大量占用 V8 的堆内存。V8 为了减少生成的机器码以缓解内存的压力,尝试了大量“延迟解析和编译(Lazy parsing and compiling)”的工作。比如对于一段代码,这段代码中的函数如果没有在初始化时被调用,则该调用过程会被“延迟”,直到第一次调用时再编译该函数的代码。

    文章日期索引 Date Index

    文章类别索引 Type Index

    文章主体 Detail

    WebAssembly 尝试研究报告 - API 之初始化、内存和表的分配

    本篇报告我们会花一点时间来详细的了解下 WebAssembly JS API 的特性和使用方法。随着 WebAssembly MVP 版本的发布,与其对接的 Web API 也有了相应的改动和部分标准化。本次报告主要研究 WebAssembly 模块初始化、内存分配、表分配的相关内容。

    一、加载和初始化

    在 JavaScript 中,WebAssembly 是一个包含所有与 WebAssembly 相关功能的命名空间对象(同 Math 对象一样),因此它并没有构造函数。WebAssembly 包含一些方法和对象用来加载和初始化 WebAssembly 模块,相关的方法和对象列出如下:

    
    // 方法
    WebAssembly.compile();      // 用来从二进制代码编译出一个 WebAssembly.Module 对象;
    WebAssembly.instantiate();  // 初始化一个 WebAssembly.Module 对象,同时传递需要的初始化参数;
    WebAssembly.validate();     // 用来验证对应的二进制代码是否是来自一个完整的 Wasm 模块; 
    // 对象(构造函数)
    WebAssembly.Module();       // WebAssembly.Module 对象的构造函数;
    WebAssembly.Instance();     // WebAssembly.Instance 对象的构造函数;
    

    我们直接通过具体的例子来了解上述 API 的使用方法,对应的 C 语言代码如下所示。代码很简单,一个预置函数 print_number 和一个调用了预置函数的加法函数 add,我们只需要在 JS 层初始化 Wasm 模块的时传递一个 print_number 函数实体即可。

    
    int print_number (int i);
    
    int add (int a, int b) { 
      print_number(a + b);
      return a + b;
    }
    

    第一种初始化方式如下代码所示。我们均使用 WebAssembly 对象上的异步方法来进行 Wasm 的加载和初始化。整个初始化一共分为三个步骤:验证,编译,实例化。不论是通过 WebAssembly 对象的方法还是单独使用 WebAssembly 下各个对象的构造函数来初始化,其整体流程都是一样的。主要区别只是同步方式和异步方式两种不同策略而已。

    
    var importObject = {
      env: {
        print_number: function(number) {
          console.log(number);
        }
      }
    }
    
    if (WebAssembly.validate(wasmCode)) {
      WebAssembly.compile(wasmCode).then(module => {
        WebAssembly.instantiate(module, importObject).then(instance => {
          var add = instance.exports.add;  // 导出的函数
          var memory = instance.exports.memory;   // 获得内存对象
          console.log(memory instanceof WebAssembly.Memory);
          console.log(add(1, 2));
        });
      });
    }
    

    第二种初始化使用 WebAssembly 提供的多种构造函数进行同步的初始化过程,具体代码如下所示。

    
    var importObject = {
      env: {
        print_number: function(number) {
          console.log(number);
        }
      }
    }
    
    if (WebAssembly.validate(wasmCode)) {
      var module = WebAssembly.Module(wasmCode);
      var instance = WebAssembly.Instance(module, importObject);
      var add = instance.exports.add;
      var memory = instance.exports.memory;
      console.log(memory instanceof WebAssembly.Memory);
      console.log(add(1, 2));
    }
    

    第三种初始化方式同第一种十分相似,不同的是我们在这里没有首先使用 WebAssembly.compile 来编译 Wasm 的二进制代码,而是直接使用 WebAssembly.instantiate 对 Wasm 的二进制代码进行了实例化,这便是 WebAssembly.instantiate 的第二种使用场景。在第一种方法中,我们在初始化的过程中会产生一个中间对象即 WebAssembly.Module 对象,在这个对象中保存了已经编译好的无状态 WebAssembly 代码,这些代码可以通过 Web Workers 高效的传递给子 Worker 进行使用,或者将其存储在本地的 IndexedDB 当中,当有需要时可以从本地 DB 中取出多次的进行再实例化(Worker 传递和本地数据库存储的相关内容我们会在下一篇报告中讲述)。因此相对来说,第三种初始化方法更适合用于不需要本地存储等情况下的快速 WebAssembly 实例化。具体代码如下所示。

    
    var importObject = {
      env: {
        print_number: function(number) {
          console.log(number);
        }
      }
    }
    
    if (WebAssembly.validate(wasmCode)) {
      // 第一个参数直接使用 wasmCode 二进制代码,而非 WebAssembly.Module 对象;
      WebAssembly.instantiate(wasmCode, importObject).then(result => {
        var instance = result.instance;
        var add = instance.exports.add;
        var memory = instance.exports.memory;
        console.log(memory instanceof WebAssembly.Memory);
        console.log(add(1, 2));
      });
    }
    

    除此之外,WebAssembly.Module 还有两个比较常用的静态方法 importsexports,可以通过传入一个 WebAssembly.Module 来获得该 Wasm 模块的导出接口和需要导入的函数占位符,代码如下。

    
    var wasmModule = new WebAssembly.Module(wasmCode);
    console.log(WebAssembly.Module.imports(wasmModule));
    console.log(WebAssembly.Module.exports(wasmModule));
    

    二、内存分配

    我们可以在 JS 层为 Wasm 模块手动分配固定大小的内存块供 Wasm 模块来使用,这样做的好处是我们可以使用 JS 在模块编译之前或获取并创建内存的初始内容。为了实现让 Wasm 模块使用我们从 JS 初始化的内存,我们需要手动修改 Wast 文本中的内容。Wast 是 Wasm 模块的可读文本格式,我们首先将编写好的 C/C++ 源码编译成 Wast 可读文本,然后将文本中内存使用方式改成使用外部引入的内存,最后再通过 WABT 提供的工具将其继续编译成 Wasm 二进制格式。Wast 文本中修改内存使用方式的部分示例代码如下,其他代码可以在 Github 上查阅。关于 Wast 文本的基本语法可以参考 MDN 的相关文档

    
    ;; 修改前
    (module
      (table 0 anyfunc)
      (memory $0 1)
      (export "memory" (memory $0))
      (export "plus" (func $plus))
      ...
    )
    
    
    ;; 修改后
    (module
      (import "env" "memory" (memory $0 1))
      (table 0 anyfunc)
      (export "memory" (memory $0))
      (export "plus" (func $plus))
      ... 
    )
    

    对应的我们需要在 JS 中初始化一个内存对象。Wasm 的所有内存大小都是以“页”作为单位的,默认的一页大小为 64KB,在传递内存对象到 Wasm 模块时至少要保证该内存对象的大小大于等于一页。部分 JS 代码如下所示。

    
    var memory = new WebAssembly.Memory({initial: 2, maximum: 100});
      var importObject = {
          env: {
              memory: memory
          }
      } 
    )
    

    WebAssembly.Memory 构造函数的参数为一个内存对象描述符,其中 initial 参数表示该内存对象的初始化大小(以页为单位),maximum 参数表示该内存块的最大可用大小(以页为单位)。

    三、表分配

    WebAssembly 中的 Table 主要用来存储动态函数的引用。现在来看,Table 的一个主要应用场景是可以在 Wasm 模块之间进行动态链接。也就是说我们可以通过 Table 和 Memory 的共享来使两个 Module 之间通过 Table 进行“交互”。一个简单的使用了 Table 的 Wasm 模块其可读文本内容如下所示。其中第一部分指定 Table 的大小为2,即只能最多存储两个函数的引用。普通函数的声明部分没有任何变化。接下来的元素段中我们为 Table 分配了两个函数引用,元素段是 Table 的主要初始化过程。由于在调用 Table 中函数时要保证调用函数的函数签名和索引同时正确函数才可以被正常调用。

    
    (module
      (table 2 anyfunc)                        ;; 指定 Table 大小;
      (func $f1 (result i32)
        i32.const 42)
      (func $f2 (result i32)
        i32.const 13)
      (elem (i32.const 0) $f1 $f2)             ;; 元素段,为 Table 分配函数引用 $f1 和 $f2,表空间的起始地址偏移为0;
      (type $return_i32 (func (result i32)))   ;; 定义函数签名,即 $return_i32 类型为一个返回值为 i32 类型的函数;
      (func (export "callByIndex") (param $i i32) (result i32)
        get_local $i                           ;; 参数入执行栈;
        call_indirect $return_i32)             ;; 执行 Table 中索引为 $i 的函数,并且验证签名类型为 $return_i32; 
    )
    

    接下来我们来看一下怎样通过 Table 在两个不同的 Wasm 模块之间进行“通信”。通过同一个 Memory 和 Table 进行初始化的 Wasm 模块便可以共享同一个 Linear Memory 段和同一个 Table,由于 Table 中存储了不同模块不同方法的引用,因此我们便可以通过间接调用表方法的方式来达到模块间互相调用方法的目的(跟一个桌面应用的所有 DLL 动态链接库共享同一个进程内存地址一样),首先来看第一个模块的结构,如下所示。

    
    (module
      (import "js" "memory" (memory 1))        ;; 使用导入的内存;
      (import "js" "table" (table 1 anyfunc))  ;; 使用导入的 Table;
      (elem (i32.const 0) $shared0func)        ;; 初始化 Table,索引0处放入函数 $shared0func;
      (func $shared0func (result i32)
       i32.const 0                             ;; 常量0入执行栈;
       i32.load)                               ;; 取出执行栈的第一个值作为参数,取出该参数对应内存位置的值;
    )
    

    接下来是第二个模块的结构。

    
    (module
      (import "js" "memory" (memory 1))        ;; 使用导入的内存(与第一个模块一样);
      (import "js" "table" (table 1 anyfunc))  ;; 使用导入的 Table(与第一个模块一样);
      (type $void_to_i32 (func (result i32)))  
      (func (export “doIt”) (result i32)
       i32.const 0                             ;; 常量0入执行栈;
       i32.const 42                            ;; 常量42入执行栈;
       i32.store                               ;; 取出执行栈的前两个值作为参数,将常量42存储内存偏移为0的位置;
       i32.const 0                             ;; 常量0入执行栈;
       call_indirect $void_to_i32)             ;; 调用 Table 中索引位置为0的函数,并且函数签名中返回值的类型是 i32;
    )
    

    这里要注意的是 Wasm 独有的执行栈与线性内存分离的设计,所有的操作数都会被事先放到执行栈中。操作符直接从执行栈中取出对应个数的操作数。这种分离结构也有利于 Wasm 的执行安全,保证运行过程中数据不会被篡改。Wasm 模块间的动态链接过程大致如下图所示。

    当然 Table 的用途不止是可以用来做模块之间的动态链接,还可以做重载函数在 JS 端的调用容器。这些特性我们会在 Post-MVP 阶段再仔细进行研究。

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

    一语浏览 Detail

    其他 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

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

    计算机原理 CP

    HTTP1.1存在的问题:

    1、TCP连接数有限(最多6-8个),导致分片(Sharding)技术滥用,一个网站的所有资源被分布在多个主机上;

    2、线头阻塞(Head of Line Blocking)问题,服务器处理请求需要按顺序进行,即发送请求时可以多个请求放到一个 TCP 连接中(Pipelining),但接收需要按顺序一个一个来处理;

    3、可选细节过多,标准过于庞大;

    4、重复的头部内容;

    HTTP2的优势:

    1、多路复用的流,可以通过单一的 HTTP2 请求来发起多重的请求-响应消息,即请求发送和接受均并行,且不需要多个 TCP 连接;

    2、使用 HPACK 算法来压缩首部内容;

    3、服务端推送:浏览器发送一个请求,返回多个相关资源的响应;

    4、二进制分帧层:位于传输层和应用层之间,首部信息被封装到 HEADER 帧中,请求体被封装到 DATA 帧中。通过单连接多复用来解决 TCP 连接到慢启动问题;

    SPDY 与 HTTP2 的区别:

    大部分特性与 HTTP2 保持一致,包括服务器端推送,多路复用和帧作为传输的最小单位。但 SPDY 的头部压缩使用的是 DEFLATE 算法,而 HTTP2 使用的是 HPACK 算法,压缩率更高。

    另一种协议 QUIC(Quick UDP Internet Connections):“HTTP2 on UDP”

    1、使用 QPACK 代替 HPACK;

    计算机原理 CP

    内存对齐主要遵循下面三个原则:

    结构体变量的起始地址能够被其最宽的成员大小整除;

    结构体每个成员相对于起始地址的偏移能够被其自身大小整除,如果不能则在前一个成员后面补充字节;

    结构体总体大小能够被最宽的成员的大小整除,如不能则在后面补充字节;

    前端 Javascript

    在某些情况下,JS 引擎的优化 Pre-Parse 过程会被浪费。比如某些在 JS 文件加载时就运行的函数在进行 Pre-Parse 之后还需要再进行一次 Full-Parse,之前的 Pre-Parse 阶段完全浪费。这种情况下可以使用 IIFE 来省去这个 Pre-Parse 阶段(V8 支持)。

    
    var constants = (function constants(){
        function sayHi(name){
            var message = "Hi " + name + "!"
            print(message)
        }
    
    sayHi("Sparkle")
    })()
     
    前端 Javascript

    日常开发如果遇到后端接口传过来大整数,比如订单号,由于 JS 最大安全数位数有限,所以可能会发现解析出的数据与和传过来的字符串数据值不相符。可以通过正则进行对应字段的替换,讲数字类型替换成字符串(注意标准 JSON 格式是双引号)

    
    replaceNumberToStringInJson(fields, json) {
      let result = json
      fields.forEach((field) => {
        result = result.replace(new RegExp(`"${field}":\\s([\\d.]+)`, 'g'), `"${field}": "$1"`)
      })
    
      return result
    }
     
    前端 Javascript

    使用npm check来检查 NPM 包的更新状态。

    
    npm check -u -g  # 检测全局依赖
    npm check -u     # 检测当前项目的依赖
    

    代码库 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》。