位运算 | ||
0. 原理 |
|
|
1. 统计两个数的二进制表示有多少位不同 | 第一次可做出Ok |
|
2. 数组中唯一一个不重复的元素 | 第一次可做出Ok |
|
3. 找出数组中缺失的那个数 | 第一次可做出,类上 |
|
4. 数组中不重复的两个元素 | 第一次未做出 | ※ |
5. 翻转一个数的比特位 | 思考后可做出 |
|
6. 不用额外变量交换两个整数 |
|
|
7. 判断一个数是不是 2 的 n 次方 | 做法可简化 | ※ |
8. 判断一个数是不是 4 的 n 次方 | 思考后可做出 |
|
9. 判断一个数的位级表示是否不会出现连续的 0 和 1 | 有其他做法可参考 | ※ |
10. 求一个数的补码 | 思考后可做出 | ※ |
11. 实现整数的加法 | 有其他做法可参考 | ※ |
12. 字符串数组最大乘积 | 思考后可做出 | ※ |
13. 统计从 0 ~ n 每个数的二进制表示中 1 的个数 | 第一次未做出 | ※ |
0. 原理
基本原理
0s 表示一串 0,1s 表示一串 1。
x ^ 0s = x x & 0s = 0 x | 0s = x
x ^ 1s = ~x x & 1s = x x | 1s = 1s
x ^ x = 0 x & x = x x | x = x
- 利用 x ^ 1s = ~x 的特点,可以将一个数的位级表示翻转;利用 x ^ x = 0 的特点,可以将三个数中重复的两个数去除,只留下另一个数。
- 利用 x & 0s = 0 和 x & 1s = x 的特点,可以实现掩码操作。一个数 num 与 mask:00111100 进行位与操作,只保留 num 中与 mask 的 1 部分相对应的位。
- 利用 x | 0s = x 和 x | 1s = 1s 的特点,可以实现设值操作。一个数 num 与 mask:00111100 进行位或操作,将 num 中与 mask 的 1 部分相对应的位都设置为 1。
1^1^2 = 2
01011011 &
00111100
--------
00011000
01011011 |
00111100
--------
01111111
位与运算技巧
- n&(n-1) 去除 n 的位级表示中最低的那一位 1。例如对于二进制表示 01011011,减去 1 得到 01011010,这两个数相与得到 01011010。
- n&(-n) 得到 n 的位级表示中最低的那一位 1。-n 得到 n 的反码加 1,也就是 -n=~n+1。例如对于二进制表示 10110100,-n 得到 01001100,相与得到 00000100。
- n-(n&(-n)) 则可以去除 n 的位级表示中最低的那一位 1,和 n&(n-1) 效果一样。
移位运算
- >> n 为算术右移,相当于除以 2n,例如 -7 >> 2 = -2。
- << n 为算术左移,相当于乘以 2n。-7 << 2 = -28。
mask 计算
- 要获取 111111111,将 0 取反即可,~0。
- 要得到只有第 i 位为 1 的 mask,将 1 向左移动 i-1 位即可,1<<(i-1) 。例如 1<<4 得到只有第 5 位为 1 的 mask :00010000。
- 要得到 1 到 i 位为 1 的 mask,(1<<i)-1 即可,例如将 (1<<4)-1 = 00010000-1 = 00001111。
- 要得到 1 到 i 位为 0 的 mask,只需将 1 到 i 位为 1 的 mask 取反,即 ~((1<<i)-1)。
1. 统计两个数的二进制表示有多少位不同
461. Hamming Distance (Easy)
https://leetcode-cn.com/problems/hamming-distance/
2. 数组中唯一一个不重复的元素
136. Single Number (Easy)
https://leetcode-cn.com/problems/single-number/
3. 找出数组中缺失的那个数
268. Missing Number (Easy)
https://leetcode-cn.com/problems/missing-number/
class Solution {
public:
int missingNumber(vector<int>& nums) {
int ret=nums.size();
for(int i=0;i<nums.size();i++)
ret^=nums[i]^i;
return ret;
}
};
4. 数组中不重复的两个元素
260. Single Number III (Medium)
https://leetcode-cn.com/problems/single-number-iii/
两个不相等的元素在位级表示上必定会有一位存在不同。
将数组的所有元素异或得到的结果为不存在重复的两个元素异或的结果。
diff &= -diff 得到出 diff 最右侧不为 0 的位,也就是不存在重复的两个元素在位级表示上最右侧不同的那一位,利用这一位就可以将两个元素区分开来。
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
vector<int> ret(2,0);
int dif=0;
for(int num:nums) dif^=num;
dif&=(-dif);
for(int num:nums)
if((num&dif)==0) ret[0]^=num;
else ret[1]^=num;
return ret;
}
};
5. 翻转一个数的比特位
190. Reverse Bits (Easy)
https://leetcode-cn.com/problems/reverse-bits/
6. 不用额外变量交换两个整数
a = a ^ b;
b = a ^ b; //原a
a = a ^ b; //原b
或者
a = a + b;
b = a - b; //原a
a = a - b; //原b
7. 判断一个数是不是 2 的 n 次方
231. Power of Two (Easy)
https://leetcode-cn.com/problems/power-of-two/submissions/
class Solution {
public:
bool isPowerOfTwo(int n) {
return n>0&&(n&(n-1))==0;
}
};
8. 判断一个数是不是 4 的 n 次方
342. Power of Four (Easy)
https://leetcode-cn.com/problems/power-of-four/
9. 判断一个数的位级表示是否不会出现连续的 0 和 1
693. Binary Number with Alternating Bits (Easy)
https://leetcode-cn.com/problems/binary-number-with-alternating-bits/submissions/
- O(1)时间复杂度
对于 1010 这种位级表示的数,把它向右移动 1 位得到 101,这两个数每个位都不同,因此异或得到的结果为 1111。
class Solution {
public:
bool hasAlternatingBits(int n) {
long long a=n^(n>>1);
return (a&(a+1))==0;
}
};
- O(logN)时间复杂度
class Solution {
public:
bool hasAlternatingBits(int n) {
for(int i=n>>1,ret=n&1;i>0;ret=i&1,i>>=1)
if((i&1)^ret==0) return false;
return true;
}
};
10. 求一个数的补码
476. Number Complement (Easy)
https://leetcode-cn.com/problems/number-complement/
class Solution {
public:
int findComplement(int num) {
int ret=0;
for(int j=1;num>0;num>>=1,j<<=1)
if((num&1)==0) ret|=j;
return ret;
}
};
11. 实现整数的加法
371. Sum of Two Integers (Easy)
https://leetcode-cn.com/problems/sum-of-two-integers/submissions/
a ^ b 表示没有考虑进位的情况下两数的和,(a & b) << 1 就是进位。
递归会终止的原因是 (a & b) << 1 最右边会多一个 0,那么继续递归,进位最右边的 0 会慢慢增多,最后进位会变为 0,递归终止。
class Solution {
public:
int getSum(int a, int b) {
return (b==0)?a:getSum((a^b),((unsigned int)a&b)<<1);
}
};
12. 字符串数组最大乘积
318. Maximum Product of Word Lengths (Medium)
https://leetcode-cn.com/problems/maximum-product-of-word-lengths/
class Solution {
public:
int maxProduct(vector<string>& words) {
size_t n=words.size(),ret=0;
vector<int> w(n,0);
for(int i=0;i<n;i++){
for(auto c:words[i])
w[i]|=(1<<(c-'a'));
for(int j=0;j<i;j++)
if((w[i]&w[j])==0)
ret=max(ret,words[i].size()*words[j].size());
}
return ret;
}
};
13. 统计从 0 ~ n 每个数的二进制表示中 1 的个数
338. Counting Bits (Medium)
https://leetcode-cn.com/problems/counting-bits/
对于数字 6(110),它可以看成是 4(100) 再加一个 2(10),因此 dp[i] = dp[i&(i-1)] + 1;
class Solution {
public:
vector<int> countBits(int num) {
vector<int> ret(num+1,0);
for(int i=1;i<=num;i++)
ret[i]=ret[i&(i-1)]+1;
return ret;
}
};