漫画算法-小灰的算法之旅(21)
文章目录
1. 如何判断一个数是否为2的整数次幂
Q:实现一个方法,来判断一个正整数是否是2的整数次幂(如16是2的4次方,返回true;18不是2的整数次幂,则返回false).要求性能尽可能高。
方法一(暴力枚举)
思路:
利用一个整形变量,让它从1开始,不断乘以2,将每一次乘2的结果和目标整数进行比较。
创建一个中间变量temp,初始值为1。然后进入一个循环,每次循环都让temp和目标整数相比较,如果相等,则说明目标整数是2的整数次幂,如果不相等,则让temp增大一倍,继续循环并进行比较。当temp的值大于目标整数时,说明目标整数不是2的整数次幂。
例如:给出一个整数19,则存在
1 X 2=2;
2 X 2=4;
4 X 2=8;
8 X 2 =16;
16 X 2=32; 因为32>19,所以19不是2的整数次幂。
时间复杂度
如果目标整数的大小是n,则此方法的时间复杂度是O(logn)
代码实现
public static boolean isPowerOf2(int num){
int temp=1;
while(temp<=num){
if(temp==num){
return true;
}
temp=temp*2;
}
return false;
}
public static void main(String[] args){
System.out.println(isPowerOf2(32));
System.out.println(isPowerOf(19));
}
golang实现
func isPowerOf2V1(num int) bool {
temp :=1
for temp<=num {
if temp==num {
return true
}
temp=temp*2
}
return false
}
func main(){
log.Println("暴力枚举法")
log.Println(isPowerOf2V1(32))
log.Println(isPowerOf2V1(19))
}
方法二(枚举&&移位)
思路
利用一个整型变量,让它从1开始不断的向左移位,因为移位的性能比乘法高很多。
时间复杂度
采用移位运算,确实有一定的优化,但是咩有改变该算法的时间复杂度因此依旧是O(logn).
代码实现
public static boolean isPowerOf2V2(int num){
int temp=1;
while(temp<=num){
if(temp==num){
return true;
}
temp=temp<<1;
}
return false;
}
golang实现
func isPowerOf2V2(num int) bool {
temp :=1
for temp<=num {
if temp==num {
return true
}
temp=temp<<1
}
return false
}
方法三(按位与运算)
思路
如果一个整数是2的整数次幂,那么当它转化成二进制时,只有最高位是1,其它位都是0。如下图
此时,如果将这些2的整数次幂都各自减1之后,会发现它们都二进制数字就全都变成1了。
因为我们知道0和1按位与运算都结果都是0。如果我们将原数值(2的整数次幂)和它减1的结果进行按位与运算,即(n&(n-1)).我们会发现两者的按位与运算结果必然为0。因此,如果一个整数不是2的整数次幂,那么(n&(n-1))的结果必定不为0。
时间复杂度
按位与运算的是时间复杂度位O(1)
代码实现
public static boolean isPowerOf2V3(int num){
return (num&(num-1))==0;
}
golang实现
//按位与运算 巧解 n&(n-1)==0
func isPowerOf2V3(num int) bool {
return (num&(num-1))==0
}
func main() {
log.Println("按位与运算")
log.Println(isPowerOf2V3(32))
log.Println(isPowerOf2V3(19))
}
总结
巧妙的利用二进制的按位与运算实现算法求解。计算机基础不能丢啊。