这是我参与「第五届青训营 」伴学笔记创作活动的第3天。
今天想讲一下我学到的判断一个数字是否为为4的幂的几种方法,可以体现代码优化的过程。
题目:判断一个数是否为4的幂(1是4的0次幂)
方法一: 常规思路,一个while循环,让num一直除以4,如果num取余4不是0,那返回false,直到num===1,返回true。
(不要忘记每次对输入类型进行转换,将其转换为数字类型。)
function isPowerOfFour(num) {
num = parseInt(num);
while(num > 1) {
if(num % 4) return false;
num /= 4;
}
return num === 1;
}
方法二: (位运算)用num & 0b11来判断num的二进制数后两位是不是0(因为4的幂的二进制编码一定是1000000,即1后面偶数个0),如果后两位都是0的话,那就让num右移两位,再进行下一轮while判断),直到num===1返回true。
function isPowerOfFour(num) {
num = parseInt(num);
while(num > 1) {
if(num & 0b11) return false;
num >>>=2;
}
return num === 1;
}
方法三: (位运算)这里有里三个判断条件,用这三个判断条件可以一次判断出num是否为4的幂。
num>0自不用说,num & (num-1)===0可以判断num是否是2的幂,即1后面多个0。
一个正整数位与一个他减一的二进制数,会让这个正整数二进制中的1减少一个。
例如:11110 & 11101 = 11100;
11111 & 11110=11110
10000 & 01111 = 00000 (低位少了一个1)
即我们知道了,如果想是4的幂,那对应的二进制数的偶数位上不能是1,比如10000,只能是从低到高奇数位上有一个1,后面全是0。(num & 0xAAAAAAAAAAAAA) === 0可以判断num对应的二进制数后面是不是1加偶数个0。
用num位与一串1010101010可以判断出num是否偶数位上没有1。而0xAAAAAAAAAAA这个数是根据JS浮点数的位数决定的值。
这三个条件同时满足的话,可判断出num是否是4的幂。这是一个时间复杂度为O(1)的算法。比前面的方法要节省时间。
function isPowerOfFour(num){
num = parseInt(num);
return num > 0 &&
(num & (num - 1)) === 0 &&
(num & 0xAAAAAAAAAAAAA) === 0;
}
方法四: 既然是JS,可以使用正则表达式来判断。
JS中不检查输入类型,可以将输入直接转为二进制的字符串,比如16转为'10000',再用正则表达式匹配字符串是否是1后面跟偶数个0。是的话num即是4的幂。
function isPowerOfFour(num) {
num = parseInt(num).toString(2);
return /^1(?:00)*$/.test(num);
}
总结:本题需要注意的是每次对输入进行parseInt()转换成数字,以及追求时间复杂度更低的算法。