x
x
54.81.0.*

最新文章 Latest Blogs

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    文章日期索引 Date Index

    文章类别索引 Type Index

    文章主体 Detail

    WebAssembly 深入研究报告 - 二进制编码

    本篇报告我们来看一下 WebAssembly 的二进制编码格式。为什么 Wasm 会选择一种新的二进制编码格式,而不直接使用 Asm.js 的 ASCII 文本格式?Wasm 的 OPCode 操作码格式是怎样的?Wasm 模块在内存中的格式,以及用于验证模块的魔术字符是什么?。

    1、二进制编码的数字类型

    在 MVP 中用于编码 WebAssembly 二进制格式的数字类型有如下几种:整数类型 uint8uint16uint32,可以很直观的看出来这三种类型分别对应无符号的8位、16位和32位整数。所有这几种整数类型在内存中都是以“小端字节序”的方式排列的,即低位字节排放在内存的低地址端,高位字节排放在内存的高地址端(如上图所示)。除了固定长度的整数外,Wasm 还支持基于小端字节序的 LEB128 可变长度编码,其无符号类型表示为varuint1varuint7varuint32,有符号类型表示为varint7varint32varint64。LEB128 编码以每7位为一个整体对一个二进制整数进行编码。首先将每7位组成一个字节,然后再根据是否还有后续字节,分别对该字节的最高位填入0或1,最后将这一系列的字节以小端字节序的方式存入内存。因此在解码 LEB128 编码的序列时要注意只有每个字节的最后7位才是有效数字。下面是一个无符号整数的 LEB128 编码例子。这几种数字编码类型都是用来编码 Wasm 原始二进制格式的。

    
          10011000011101100101  In raw binary
         010011000011101100101  Padded to a multiple of 7 bits
     0100110  0001110  1100101  Split into 7-bit groups
    00100110 10001110 11100101  Add high 1 bits on all but last group to form bytes
        0x26     0x8E     0xE5  In hexadecimal
    0xE5 0x8E 0x26              Output stream
    

    2、指令操作码(OpCode)

    由于 MVP 的指令个数只有不到 256 个,因此 Wasm 的指令操作码现阶段全部编码为一个比特的大小,在未来会通过增加 Prefixes 的方式来扩展更多的指令。OpCode 主要用在汇编程序解析汇编指令时,汇编程序会将对应的每条 Asm 指令转换成一个对应的 OpCode,以便计算机后续的指令执行。每一个 OpCode 由六个数据域组成,如下图所示。其中只有 Code 域是必须存在的,其他均为可选域。

    3、语言层次的类型

    我们可以在 WebAssembly 的可读文本格式 Wast 文件中查看一个 Wasm 模块在内存中的逻辑表示,模块的逻辑使用 S 表达式进行表达。在 Wast 中可以看到很多常用的类型标识,如下所示的代码:

    
    (module
      (import "env" "printInt" (func $printInt (param i32)))
      (import "env" "printFloat" (func $printFloat (param f32)))
      (import "env" "print" (func $print (param i32 i32)))
    
      (memory $memory 1)
      (data (i32.const 0) "
    ")
      (data (i32.const 1) "Hello World!")
    
      (func $endl
        (call $print (i32.const 0) (i32.const 1)))
    
      (func $main
        (call $printInt (i32.const 9))
        (call $endl)
        (call $printFloat (f32.const 6.28))
        (call $endl)
        (call $print (i32.const 1) (i32.const 12))
        )
    
      (export "main" (func $main))
      (export "memory" (memory $memory))
    )
    

    比如上述 S 表达式中出现的 i32f32,分别代表 Wasm 模块中的一个32位整数和一个32位浮点数。func 代表一个函数类型等。所有语言层面的类型在模块的二进制代码中都以一个负的 varint7 值作为每种类型编码值的第一位作的区分字符,其中一部分类型如下表所示。

    
    -0x01/0x7f  i32
    -0x02/0x7e  i64
    -0x03/0x7d  f32
    -0x04/0x7c  f64
    -0x10/0x70  anyfunc
    -0x20/0x60  func
    -0x40/0x40  block_type
    

    4、模块结构

    
    int main() { 
      return 42;
    } 
    

    我们将如上所示的 C 源码编译成一个 Wasm 模块,该模块的二进制内容如下所示(以十六进制表示):

    
    0061 736d 0100 0000 0185 8080 8000 0160
    0001 7f03 8280 8080 0001 0004 8480 8080
    0001 7000 0005 8380 8080 0001 0001 0681
    8080 8000 0007 9180 8080 0002 066d 656d
    6f72 7902 0004 6d61 696e 0000 0a8a 8080
    8000 0184 8080 8000 0041 2a0b 
    

    接下来我们来看下该 Wasm 模块的二进制编码格式。首先,模块由两个前置字段作为整个模块的起始字段。第一个字段的内容为 0x6d736100,是 Wasm 模块的魔术字符,如果将该字段的内容转换成 ASCII 码格式可以发现其内容是“(null)asm”。第二个字段指定了该模块的版本号,内容为 0x1。由于 Wasm 对其二进制格式的编码采用了小端字节序的方式,因此我们可以看到上述二进制编码的前两个字节恰好是魔术字符的最后两个字节。浏览器在解析 Wasm 的二进制格式时会把先读到二进制代码放入内存的低位空间,后续读取到的代码放到高位空间。版本之后的内容是由一个个“段”组成的。每个段首先以一个7位的 varuint7 类型 ID 作为起始,接下是一个变长的 varuint32 数代表了当前段以字节为单位的大小。我们也可以使用 hexdump 来直观的查看一个 Wasm 二进制模块的结构,使用命令:hexdump -C program.wasm,结果显示如下。

    我们先根据每个 Section 的 ID 将整个模块的二进制代码分为如下所示的几个部分。

    
    SectionNamae   Seperator           PayloadSize  PayloadContent
    Tpye           01 85 80 80 80 00   (5bytes)     01 60 00 01 7f
    Function       03 82 80 80 80 00   (2bytes)     01 00
    Table          04 84 80 80 80 00   (4bytes)     01 70 00 00
    Memory         05 83 80 80 80 00   (3bytes)     01 00 01
    Global         06 81 80 80 80 00   (1bytes)     0
    Export         07 91 80 80 80 00   (17bytes)    02 06 6d 65 6d 6f 72 79 02 00 04 6d 61 69 6e 00 00
    Code           0a 8a 80 80 80 00   (10bytes)    01 84 80 80 80 00 00 41 2a 0b
    

    通过上面给出的分类表我们可以看到,根据每个 Section 的头部特征我们可以将整个二进制代码分解为除“魔术字符”和“版本号”外的多个“段”,每个“段”都有自己对应的功能和结构。由于我们的代码中没有引入自定义“段”,因此这里列出的该模块内所有“段”的 ID 均不为0。这样每个“段”的内容均只包含三个字段部分:"段ID",“段大小”以及“段内容”。在上面的表格中我将“段ID”和“段大小”两个字段的内容统一整合为一个 “Seperator” 字段。“Seperator” 字段的第一位代表了该“段”的类型,接下来的五位是一个 varuint32 类型,代表了该“段”内容部分的长度。比如第一个 Type “段”的“段大小”字段值为5,因此接下来的5个比特均为该“段”的“段内容”数据。

    每个不同类型的“段”对应的“段内容”又对应着不同的结构,我们这里以 Export “段”和 Code “段”为例进行讲解,其他类型基本类似。

    如上图所示的 Export Section 的“段内容”结构。一个 Export Section 结构被分为两部分,第一部分为 Export Entity 的个数,第二部分为对应的 Export Entity 实体内容。我们可以根据上图将该 Wasm 模块的 Export Section 分为如下部分。该模块需要导出的对象有两个,每个导出对象的实体又分别对应着“域标志长度”,“域标示”,“域类型“和”域索引“。

    
    Export Entity 个数:        02 
    第一个 Export Entity 结构:  06 6d 65 6d 6f 72 79 02 00 
    第二个 Export Entity 结构:  04 6d 61 69 6e 00 00
    

    接着我们对第一个 Export Entity 再进行分解,结果如下所示。该 Export Entity 的”域标志长度“为6,因此接下来的6个比特为该 Export Entity 的”域标志“,其内容对应的 ASCII 码为”memory“。域类型02代表着 Memory 类型。域索引值为0。以此类推,第二个 Export Entity 其实就是我们在 C 源码中导出的 main 函数,其”域标志“对应的 ASCII 码为”main“,域类型00代表着 Function 类型,域索引值为0。接下来我们再来看 Code Section 的结构。

    
    域标志的长度:    06
    域标示:         6d 65 6d 6f 72 79
    域类型:         02
    域索引:         00
    

    Code Section 代表着导出函数的函数体内容,该“段”对应的函数个数要与 Function Section 相对应。可以看到在 Function Section 中得到的该模块的导出函数个数为1,因此对应的 Code Section 中只有一个函数体的内容。同时,Code Section 中的第i个函数体定义也要对应着 Type Section 中的第i个函数签名(Type Section 中定义了各个函数的函数、参数和返回值类型)。根据 Code Section 的结构我们得到如下分析结果。

    
    函数体的内容:     84 80 80 80 00 00 41 2a 0b
    函数体的大小:     84 80 80 80 00 
    本地变量个数:     00
    函数体的代码:     41 2a
    函数结束标志:     0b
    

    其中的“函数体代码”便是我们在 main 函数中写的返回语句 return 42。其他部分可以根据上图给出的 Function Section 字段进行一一对应。再回过头来看, Type Section 的最后一个字段表示对应函数的返回值类型。这里可以看到该模块的唯一一个函数的返回值是“7f”类型。再结合我们之前讲过的 Wasm 模块在语言层面的类型可以知道这是一个 i32(32位整数) 类型的值。

    发布时间 : 2017-06-20 23:14:21 作者 : 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》。