leetcode 231 2的幂

基本的优先级需要记住:
指针最优,单目运算优于双目运算。如正负号。
先算术运算,后移位运算,最后位运算。请特别注意:1 << 3 + 2 & 7等价于 (1 << (3 + 2))&7.
逻辑运算最后结合。

O(logN)

public boolean isPowOfTwo(int num) {
 	if (n == 0) return false;
 	// 2, 4, 3
 	while (n % 2 == 0) {
 		n /= 2;
 	}
 	return n == 1;
}
/*
注意如果传入负数%2结果为多少呢
-5 % 2 = -5 - (-5 / 2) * 2 = -5  - (-2 * 2) = - 5 - (-4) = -1;
-4 % 2 = - 4 - ( - 4 / 2) * 2 = -4 - (-2 * 2) = - 4 + 4 = 0;
 C/Java的处理方式:
大多数语言的处理方式都与 C/Java 一致,采用了 truncate 除法。
10 % (-3)= 1 的计算结果如下:r = 10 - (10 / -3) * -3 = 10 - (-3 x -3) = 1
-10 % 3 = -1 的计算结果如下:r = -10 - (-10 / 3) * 3 = -10 - (-3 * 3) = -1。

*/

通过位运算在O(1)时间复杂度解决问题
如何获取二进制中最右边的1: X & (-X)
如何将二进制中最右边的1置为0: X & (X - 1)

以下的两种解决方案背后的思想都是一样的:2 的幂在二进制中是有一个 1 后跟一些 0:

1 = (0000 0001)
2 = (0000 0010)
4 = (0000 0100)
8 = (0000 1000)

​不是 2 的幂的二进制中有一个以上的 1。
3=(00000011)
5 = (0000 0101)
6 = (0000 0110)
7 = (0000 0111)

除了 0,我们应该单独处理。

方法一:位运算:获取二进制中最右边的 1

leetcode 231 2的幂_第1张图片

leetcode 231 2的幂_第2张图片

检测是否为2的幂:

我们通过 x & (-x) 保留了最右边的 1,并将其他位设置为 0 若 x 为 2 的幂,则它的二进制表示中只包含一个 1,则有 x & (-x) = x。

若 x 不是 2 的幂,则在二进制表示中存在其他 1,因此 x & (-x) != x。

因此判断是否为 2 的幂的关键是:判断 x & (-x) == x。
leetcode 231 2的幂_第3张图片

时间复杂度O(1),空间复杂度O(1)

public boolean isPowerOfTwo(int nums) {
	if(n == 0) return false;
	//  return (n & (-n)) == n;  这样提交报错了,输入-2147483648 因为-2^31 = -2147483648,负数是有正数的补码加1得来的,所以负数要与它的正数异或那么要先算它的正数,那么负数的正数为负数减1再取反,由于 -2^31已经是最小的值了,如果它再减1就溢出了,所以这里要转为Long类型(不明白这里为什么要转为long型呢?测试数据有INT_MIN,再减一就溢出了,会报错。)
	long x = (long) n;
	return (x & (-x)) == x;
	/*
	这里一定要注意负数传进来与正数&之后的结果是它的正数的值,不是本身负数所以 负数传进来返回的是false 比如 
	2    					0000 0010 
	-2   1111 1101 + 1 = 	1111 1110
							0000 0010   显然结果是结果不是-2即1111 1110而是2即0000 0010, 所以返回false
*/
}

/*

*/

方法二:位运算:去除二进制中最右边的1

leetcode 231 2的幂_第4张图片
2 的幂二进制表示只含有一个 1。
x & (x - 1) 操作会将 2 的幂设置为 0,因此判断是否为 2 的幂是:判断 x & (x - 1) == 0。

时间复杂度:O(1)。空间复杂度:O(1)。

public boolean isPowerOfTwo(int n) {
	if(n == 0) return false;
	long x = (long) n;
	return (x & (x - 1)) == 0;
}

方法三: 作为2的幂一定满足n > 0

解题思路
若n = 2^x且x为自然数(即n为2的幂),则一定满足一下条件:
1 恒有 n & (n - 1) == 0,这是因为

  • n二进制最高位为1,其余所有位为0
  • n-1二进制最高位为0,其余所有为为1
    2 一定满足n > 0
    因此,通过 n > 0 且 n & (n - 1) == 0 即可判定是否满足 n = 2^x
    leetcode 231 2的幂_第5张图片
public int isPowerOfTwo(int num) {
	return n > 0 && (n & (n - 1)) == 0;
}

总结

在方法一种注意点:

1 这里一定要注意负数传进来与正数&之后的结果是它的正数的值,不是本身负数所以 负数传进来返回的是false
2 为什么要转为Long型

在方法二种注意思考

如果n 为负数的话 那么n转为long类型的x 运算x & (x - 1) 的结果是什么

在方法三中注意点 为什么n > 0,因为2的幂的结果肯定是大于0的, 0也不是2的幂.
负数取模问题

你可能感兴趣的:(LeetCode)