road-of-leetcode

解题中发现的小技巧

基本都来自其他人的答案, 不是独立自主发现的.

binary & -binary

可以取到数字二进制格式下最右侧的那个 1, 例:

let binary = 5;

assert(1 === binary & -binary);

number & 1

判断数字奇偶 (不需要解释了吧?).

a ^= b; b ^= a; a ^= b;

注意:实际应用中, 可能会因为两值引用同一个引用而导致数值直接变为 0 且不可恢复, 慎用!

这是异或计算的特性, 异或的本质就是计算两个数值在哪些二进制位上是不同的.

也就是说异或的结果中, 1 就代表本位两数字不同, 0 代表本位两数字相同.

该值再与两值中的任一值异或, 计算过程便成了:

  1. 两数值均为 1, 结果为 0:

    两数字本位不同, 数字 A 本位为 1 所以数字 B 本位为 0.

  2. 两数值均为 0, 结果为 0:

    两数字本位相同, 数字 A 本位为 0 所以数字 B 本位为 0.

  3. 数字为 1, 异或值为 0, 结果为 1:

    两数字本位相同, 数字 A 本位为 1 所以数字 B 本位为 1.

  4. 数字为 0, 异或值为 1, 结果为 1:

    两数字本位不同, 数字 A 本位为 0 所以数字 B 本位为 1.

所以:

设 c = a ^ b.

则 b = c ^ a, a = c ^ b;

javascript 数组

  1. 有洞的数组比没洞的在读取时速度慢很多

  2. 在从数组中读取一个超出数组长度的索引时, 会退化到从原型链上进行索引, 效率降低超多

(在当做 map 使且 key 全部为数字时, array 的效率是要高于 map 的)

所以:

如果你要使用数组做 map (或者是单纯的数组标记) 时, 请提前声明数组长度.

const array = new Array(1000);

这样创建出来的数组是有洞的, 但它的效率与通过 push 创建无洞数组差不多:

const array = [];

for (let i = 0; i < 1000; ++i) {
    array.push(false);
}

如果只是用来做 0 / 1 的标志位的话, Uint8Array 的效率更高:

const array = new Uint8Array(1000);

参考:

https://zhuanlan.zhihu.com/p/29650254

Uint8Array & Uint16Array …

如果是纯数字的定长数组, 用这些数字专用的数组可以比较明显的提高性能 (20ms 左右).

作用域链与递归

在递归时, 直接将变量通过参数传入下一个递归体内会比使用作用域链调用上层的变量要快得多.