这阶段刷完了 LeetCode 上有关位运算的题目,感觉位运算还是挺难,很难get到点,有空还是要去加强学习,要掌握 与&、异或^、或|、非~,还有算术左移、算术右移、无符号右移 。还有 Java 中 Integer 类中常见位运算的方法(三个)。
需要注意以下几点:
1. 与&、异或^、或|、非~
x ^ 1s = ~x
x & 0s = 0 x & 1s = x
x | 0s = x x | 1s = 1s
n&(n-1) 去除 n 的位级表示中最低的那一位
n&(-n) 得到 n 的位级表示中最低的那一位
n-n&(~n+1) 去除 n 的位级表示中最高的那一位。
2. 移位运算:
>> n 为算术右移,相当于除以 2n;
>>> n 为无符号右移,左边会补上 0。
<< n 为算术左移,相当于乘以 2n。
3. Java中位运算方法:**
static int Integer.bitCount(); // 统计 1 的数量
static int Integer.highestOneBit(); // 获得最高位
static String toBinaryString(int i); // 转换为二进制表示的字符串
- 不用额外变量交换两个整数
效率也比较快,感觉还是挺威的。a = a ^ b; b = a ^ b; a = a ^ b;
以下是相关题目:
260. 只出现一次的数字 III
题目描述:
定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。
示例 :
输入: [1,2,1,3,2,5]
输出: [3,5]
注意:
结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。
你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?
解题思路:
两个不相等的元素在位级表示上必定会有一位存在不同。将数组的所有元素异或得到的结果为不存在重复的两个元素异或的结果。
public int[] singleNumber(int[] nums) {
int diff = 0;
for (int num : nums) diff ^= num;
diff &= -diff; // 最后一位,利用这一位就可以将两个元素区分开来。
int[] ret = new int[2];
for (int num : nums) {
if ((num & diff) == 0) ret[0] ^= num;
else ret[1] ^= num;
}
return ret;
}
136.数组中唯一一个不重复的元素
题目描述:
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
解题思路:
算法应该具有线性时间复杂度,故应该使用位运算来解决问题,位运算还是比较快的。利用异或运算性质,两个相同的数异或的结果为 0
public int singleNumber(int[] nums) {
int ret = 0;
for (int n : nums) ret = ret ^ n;
return ret;
}
268.找出数组中缺失的那个数
题目描述:
给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。
示例 1:
输入: [3,0,1]
输出: 2
示例 2:
输入: [9,6,4,2,3,5,7,0,1]
输出: 8
说明:
你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现?
解题思路:
跟上题解法类似。
public int missingNumber(int[] nums) {
int ret = 0;
for (int i = 0; i < nums.length; i++) {
ret = ret ^ i ^ nums[i];
}
return ret ^ nums.length;
}
231.判断一个数是不是 2 的 n 次方
题目描述:
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
示例 1:
输入: 1
输出: true
解释: 20 = 1
示例 2:
输入: 16
输出: true
解释: 24 = 16
示例 3:
输入: 218
输出: false
解题思路:
- 可以利用 1000 & 0111 == 0 这种性质求解
class Solution { public boolean isPowerOfTwo(int n) { int res = n & (n - 1); return n > 0 && res == 0; } }
- 也利用Java API Integer.bitCount() 求解
public boolean isPowerOfTwo(int n) { return n > 0 && Integer.bitCount(n) == 1; }
##### [461统计两个数的二进制表示有多少位不同](https://leetcode-cn.com/problems/hamming-distance/)
###### 题目描述:
两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。
给出两个整数 x 和 y,计算它们之间的汉明距离。
注意:
0 ≤ x, y < 231.
示例:
输入: x = 1, y = 4
输出: 2
解释:
1 (0 0 0 1)
4 (0 1 0 0)
↑ ↑
上面的箭头指出了对应二进制位不同的位置。
###### 解题思路:
1. 可以使用 z&(z-1) 去除 z 位级表示最低的那一位。
~~~ java
public int hammingDistance(int x, int y) {
int z = x ^ y;
int cnt = 0;
while (z != 0) {
z &= (z - 1);
cnt++;
}
return cnt;
}
- 也可以按照常规思路 统计 1 的个数
class Solution { public int hammingDistance(int x, int y) { int num = x ^ y; int count = 0; String numStr = Integer.toBinaryString(num); for (char c : numStr.toCharArray()) { if (c == '1') { count++; } } return count; } }
371.实现整数的加法
题目描述:
不使用运算符 + 和 - ,计算两整数 a 、b 之和。
示例 1:
输入: a = 1, b = 2
输出: 3
示例 2:
输入: a = -2, b = 3
输出: 1
解题思路:
a ^ b 表示没有考虑进位的情况下两数的和,(a & b) << 1 就是进位。
class Solution {
public int getSum(int a, int b) {
while (b != 0) {
int carry = a & b;
a = a ^ b;
b = carry << 1;
}
return a;
}
}