题目要求
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
思路
思路一
通过位运算遍历数字的每个二进制位,如果只有一个1,那么就是2的幂次方.比如,5的二进制是 00000101
不是2的幂次方;而4的二进制是00000100
是2的幂次方.
那么现在问题转化为求一个数的二进制共有多少个1,如果只有一个,那么该数就是2的幂次方,否则不是.
那怎样求一个数字的二进制的1的个数呢?在回答这个问题之前,先简单说两个位运算的小技巧.
- 判断一个数是否是偶数
常规思路是这样的bool isOdd(int num) { if(num % 2 == 0) { return ture; }else { return false; } }
除了通过能否整除2来判断奇偶性,还可以借助位运算.
偶数在数学中通常表示为2n,n是正常数
,而奇数会表示成2n+1
.所以如果一个数是奇数,那么它的二进制的末尾肯定是1,偶数肯定为0.而任意数字与1进行按位与&运算,结果为1则末尾是1,否则不是.
bool isOdd(int num) {
if(num & 1 == 1) {
return false;
} else {
return true;
}
}
- 快速计算2的n次方
常规思路就是,循环n-1
次,数字2不断乘2.
int powerOfTwo(int power) {
int two = 2;
for(int i = 1; i < power;i++) {
two *= 2;
}
return two;
}
借助于位运算,我们可以通过左移<<来快速乘2.
int powerOfTwo(int power) {
return 1 << power;
} // 当然这个方法是有短板的,当power>=31的时候int会溢出
好了,下面说一下求一个数二进制含有1的个数的方法.
首先通过num & 1
判断数字的最后一位是不是1,然后不断进行右移操作遍历每一个二进制位,当数字变为0时,结束循环.如果1的个数超过了1,那么该数字一定不是2的幂次方,跳出循环.
bool isPowerOfTwo(int n) {
if(n <= 0) { // 2的幂次方肯定大于0
return false;
}
int count = 0; // 记录二进制中1的个数
while(n != 0) {
if(n & 1 == 1) { // 判断最后一位是不是1
count++; // 是1则计数器加一
}
n = n >> 1; // 不断右移1位遍历每一个二进制位
if(count >= 2) { // 1的个数超过了1,肯定不是2的幂次方,减少循环次数
return false;
}
}
return true;
}
思路二
思路一说了,如果一个数是2的幂次方,那么它的二进制只有一个1其它都是0,形如00010000
.我们也知道形如00010000
这样的数字减去1,就得到二进制为00001111
的数字.更巧的是00010000 & 00001111 == 0
,根据这个特点我们可以来判断数字是否是2的幂次方
bool isPowerOfTwo(int num ) {
if(num <= 0) {
return false;
}
return num & (num - 1) == 0; // 如果等于0表示数字是2的幂次方
}
关于位运算的笔记,未完待续~ 😃