本篇博客会讲解力扣“231. 2 的幂”的解题思路,这是题目链接。
这道题有3种巧妙的思路,且听我一一道来。
思路1
如果一个数是2的幂次方,则这个数的二进制中一定有且只有1位是1。比如,1的二进制是1,2的二进制是10,4的二进制是100,8的二进制是1000。所以,我们只需要在判断一个整数是正数的基础上,再判断二进制中有且只有一位是1即可。思路1和思路2都是在这一点上做文章。
我先来介绍一个神奇的表达式:n & n - 1。注意:减号(-)的优先级比按位与(&)要高,所以这个表达式等价于n & (n - 1)。这个表达式算出来的结果,刚好是n的二进制中去掉最低位的1的结果。比如,如果n的二进制是100110,则结果的二进制就是100100。知道了这一点,我们只需要判断n & n - 1的结果是否为0,就能判断n的二进制中是否有且只有一位是1,从而结合n的正负性判断n是否是2的幂次方。
bool isPowerOfTwo(int n) {
// n为正数,去掉最低位的1后是0
return n > 0 && (n & n - 1) == 0;
}
思路2
在思路1的基础上,还有一种方法可以判断n的二进制中是否只有一位是1。
这里介绍另一个奇妙的表达式:n & -n。这个表达式等价于n & (-n),即n和自己的相反数做按位与。这个表达式算出来的结果,刚好是保留n的二进制中最低位的1,其余位全是0。比如,如果n的二进制是100110,则结果的二进制就是000010(即二进制10)。知道了这一点,我们只需要判断n & -n的结果是否为n本身,就能判断n的二进制中是否有且只有一位是1,从而结合n的正负性判断n是否是2的幂次方。
bool isPowerOfTwo(int n) {
// n为正数,取出最低位的1是它自己
return n > 0 && (n & -n) == n;
}
思路3
本题还有一种巧妙的解法:判断n是不是2的幂次方,只需要判断n是不是一个很大的2的幂次方的约数。这个很大的2的幂次方不能超过int的表示范围,即INT_MAX。
bool isPowerOfTwo(int n) {
// n是一个很大的2的幂次方的约数
return n > 0 && (1 << 30) % n == 0;
}
总结
判断n是不是2的幂次方,可以转化为判断n的二进制中是否有且仅有一位是1,即判断n & n - 1是否为0,或者判断n & -n是否为n本身。当然,也可以直接判断n是不是一个很大的2的幂次方的约数。
感谢大家的阅读!