这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战。
算法的核心是创建问题抽象的模型和明确求解目标,之后可以根据具体的问题选择不同的模式和方法完成算法的设计。
一个例子:判断是否为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代替,按位与二进制11n /= 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的幂的二进制:
可以看出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