位运算问题算法简略记录
1、常用技巧
- 利用二进制进行计算
- 运算符号:
^
按位异或;&
按位与;|
按位或;~
取反;<<
算术左移;>>
算术右移 - 常见特性(0s/1s分别代表只由0或1构成的二进制数):
x ^ 0s = x
;x ^ 1s = ~x
;x ^ x = 0
x & 0s = 0
;x & 1s = x
;x & x = x
x | 0s = x
;x | 1s = 1
;x | x = x
n & (n-1)
:能去除n的位级中最低的那一位n = 11110100
;n-1 = 11110011
;n & (n-1) = 11110000
- 即,将n中最低位级,第三位的1去除了
n & (-n)
:可以得到n的位级中最低的那一位n = 11110100
;-n = 00001100
;n & (-n) = 00000100
- 即,将仅保留了n中最低位级
2、基础问题
解题思路
- 对两个数进行按位异或,统计共有多少个1即可
Java解答
class Solution {
public int hammingDistance(int x, int y) {
int distance = x ^ y;
int count = 0;
while (distance > 0) {
if (distance % 2 == 1) count++;
distance /= 2;
}
return count;
}
}
解题思路
- 注:输入的是32位的01进制数
- 使用算术左移和右移
ans = n & 1
为,将n的最低位赋予ans- ans与n一个算术左移乘2、一个算术右移除2
public class Solution {
// you need treat n as an unsigned value
public int reverseBits(int n) {
int ans = 0;
for (int i = 0; i < 32; i++) {
ans <<= 1;
ans += n & 1;
n >>= 1;
}
return ans;
}
}
解题思路
- 利用
x ^ x = 0
和x ^ 0 = x
的特点进行遍历数组;有x ^ y ^ x = y
- 如nums=[4, 2, 1, 2, 4],有
4 ^ 2 ^ 1 ^2 ^ 4 = 1
- 如nums=[4, 2, 1, 2, 4],有
Java解答
class Solution {
public int singleNumber(int[] nums) {
int ans = 0;
for (int num : nums) {
ans ^= num;
}
return ans;
}
}
3、二进制特性
如,二进制+位运算=数组的所有子集
- 长度为n的数组,生成长度为n的所有二进制,1表示选取该数字,0表示不选取,即可获得2^n个子集
解题思路
- 首先考虑2的次方n,其二进制的一定是
0…010…0
;n-1则为0…001…1
;则有n&(n-1)=0
- 其次考虑4的次方m,相较与2的次方n,n中所有1所处的位置在奇数位;将m与1431655765按位与,结果不为零即为4的次方
Java解答
class Solution {
public boolean isPowerOfFour(int n) {
return (n > 0) && ((n & (n - 1)) == 0) && ((n & 1431655765) != 0);
}
}
解题思路
- 首先为每个字符串建立长度为26的二进制数字;每个位置表示是否存在该字母
- 如果两个字符串含有重复的字母,二进制数字的按位与不为0
- 同时建立一个哈希表存储字母串到二进制数字的映射关系
- 预计算所有单词的位掩码,并将它们存储在 HashMap 中:位掩码 -> 该掩码对应的最大长度字符串。例如:单词 “aaaaaaa” 和 “a” 具有相同的掩码。
- 逐一两两比较 HashMap 中的单词。如果两个单词没有公共字母,更新最大单词长度乘积 maxProd。使用位掩码可以在常数时间内判断两个单词是否包含公共字母:(x & y) == 0
Java解答
class Solution {
public int bitNumber(char ch){
return (int)ch - (int)'a';
}
public int maxProduct(String[] words) {
Map<Integer, Integer> hashmap = new HashMap();
int bitmask = 0, bitNum = 0;
for (String word : words) {
bitmask = 0;
for (char ch : word.toCharArray()) {
// add bit number bitNumber in bitmask
bitmask |= 1 << bitNumber(ch);
}
// there could be different words with the same bitmask
// ex. ab and aabb
hashmap.put(bitmask, Math.max(hashmap.getOrDefault(bitmask, 0), word.length()));
}
int maxProd = 0;
for (int x : hashmap.keySet())
for (int y : hashmap.keySet())
if ((x & y) == 0) maxProd = Math.max(maxProd, hashmap.get(x) * hashmap.get(y));
return maxProd;
}
}
解题思路
- 由于
n & (-n)
为取n的最低位级的1;循环遍历,每有一个1,计数加一,n再减去最低位级代表的数
Java解答
class Solution {
public int[] countBits(int n) {
int[] ans = new int[n+1];
for (int i = 0; i <= n; i++) {
ans[i] = bits(i);
}
return ans;
}
private int bits(int n) {
int count = 0;
while (n > 0) {
if ((n & (-n)) != 0) {
count++;
}
n = n - (n & (-n));
}
return count;
}
}