常规方法
class Solution {
public:
bool isPowerOfFour(int num) {
if(num < 1) return false;
while(num > 1){
if(num % 4) return false;
num /= 4;
}
return num == 1;
}
};
位运算
可以参照LeetCode第 231 题:2的幂(C++)_zj-CSDN博客
4的0 ~ n次方,等于 2的0,2,4,6…2n(全为偶数) 次方。4的幂次方的二进制里,同样只有一位是置1的, 而且置1的位应该处于二进制中从右往左的数的第1//3/5/7/9…上面。比如16:
1:00000000 00000000 00000000 0000 0001
4:00000000 00000000 00000000 0000 0100
16:00000000 00000000 00000000 0001 0000
所以两个条件:二进制数只有一位置1, 置 1 的位置对应数字是奇数。
但是第二个条件怎么用代码表示呢?先强调第二个条件是建立在第一个条件满足的情况下讨论的。
比如16,二进制后8位是:0001 0000,置位的1在右往左的第5位(奇数),怎么去判断在第几位呢?
先用 num | (num-1),就变为 0001 1111,问题就变成了求二进制数里面1的个数是不是奇数。
先贴一个使用bitset的方法,几种判断条件可以合并在一起的:
v & -v 的作用就是取出右起连续的 0 以及首次出现的 1
class Solution {
public:
bool isPowerOfFour(int num) {
if(num <= 0) return false;
if((num & -num) != num) return false;//检测是否只有一位置1
return bitset<32>(num | (num-1)).count() % 2;
}
};
或者换个思路,第二个条件也可以理解为二进制数末尾有多少个0,如果是偶数个,那该数就是4的幂,否则就不是。那有怎样检测一个二进制数末尾有多少个0呢?看到一个很厉害的方法(并不能看懂):神秘常量0x077CB531,德布莱英序列的恩赐 - 游戏程序员刘宇 - 博客园
class Solution {
public:
int MultiplyDeBruijnBitPosition[32] = {
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
bool isPowerOfFour(int num) {
if(num <= 0) return false;
if((num & -num) != num) return false;//检测是否只有一位置1
int r = MultiplyDeBruijnBitPosition[(((num & -num) * 0x077CB531U)) >> 27];
return r % 2 == 0;
}
};
好吧,还有更简单的方法:
还是接着上面的第二个条件,需要判断1的位置,那就与:
10101010 10101010 10101010 10101010
进行与操作就可以,即为16进制的aaaaaaaa:
class Solution {
public:
bool isPowerOfFour(int num) {
return (num > 0) && ((num & (num - 1)) == 0) && ((num & 0xaaaaaaaa) == 0);
}
};
或者:若 x 为 2 的幂且 x%3 == 1,则 x 为 4 的幂。
class Solution {
public:
bool isPowerOfFour(int num) {
return (num > 0) && ((num & (num - 1)) == 0) && (num%3 == 1);
}
};
log换算
4的幂对2取log,除以2,判断奇偶就行
class Solution {
public:
bool isPowerOfFour(int num) {
//floor(a)返回不大于a的最大整数
return num > 0 && log2(num)/2 == floor(log2(num)/2);
}
};