【青训营】写好JS——学好算法

188 阅读2分钟

这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战

算法的核心是创建问题抽象的模型和明确求解目标,之后可以根据具体的问题选择不同的模式和方法完成算法的设计。

一个例子:判断是否为4的幂

力扣原题4的幂

给定一个整数,写一个函数来判断它是否是4的幂次方。如果是,返回true;否则,返回false

菜鸡入门

  • 负数直接排除
  • 循环除4,只要有一次不能整除就返回false
  • 循环完成返回true
var isPowerOfFour = function (n) {
  if (n <= 0) return false;
  while (n > 1) {
    if (n % 4) return false;
    n /= 4;
  }
  return true;
};

位运算

将上一步的运算换为位运算:

  • n % 4可以用n & 0b11代替,按位与二进制11
  • n /= 4可以用n >>= 2代替,右移两位
var isPowerOfFour = function (n) {
  if (n <= 0) return false;
  while (n > 1) {
    if (n & 0b11) return false;
    n >>>= 2;
  }
  return true;
};

位运算进阶

是4的幂的前提是2的幂,所以我们先进行两个判断:

  • 大于0
  • n & (n-1) === 0

如2的三次幂8,二进制为1000,7的二进制为0111,所以按位与的结果为0,进一步再判断是否为4的幂:

  • n & 0xAAAAAAAA === 0

观察4的幂的二进制:

1=0b0000 00014=0b0000 010016=0b0001 000064=0b0100 00001 = 0b0000\ 0001 \\ 4 = 0b0000\ 0100 \\ 16 = 0b0001\ 0000 \\ 64 = 0b0100\ 0000

可以看出4的幂的奇数位都为1,而0xA为二进制0b1010,所以将它们进行按位与,如果结果为0则证明其为4的幂。

var isPowerOfFour = function (n) {
  return n > 0 && (n & (n-1)) === 0 && (n & 0xAAAAAAAA) === 0;
};

巧用正则

既然上一步我们已经发现了4的幂的二进制特点:

  • 1开头
  • 后面偶数个0

那么直接利用JS的特性写一个正则就可以了:

var isPowerOfFour = function (n) {
  n = n.toString(2);
  return /^1(?:00)*$/.test(n);
};

更多位运算

lowbit操作用于截取一个数字的二进制最后一个1后面的所有位:

function lowbit(n) {
  return n & -n;
}

或者你也可以用只保留最后一个1及其之前的所有位:

function lowbit(n) {
  return n & (n-1);
}

求n的第k位二进制:

function k2(n) {
  return n >> k & 1;
}
  • 使用左移得出二的次幂:
console.log(1 << 2)		// 1*4,2的2次方
console.log(2 << 4)		// 2*16
  • 使用^切换0,1:
toggle ^= 1
  • 使用&判断奇偶性:
console.log(5 & 1)	// 1,为奇数
console.log(6 & 1)	// 0,为偶数
  • 使用^来完成值交换,比解构赋值快:
[a, b] = [b, a]

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