LeetCode 位运算
位运算包括:
- 与 &
- 或 |
- 异或 ^
- 取反 ~
- 左移 «
- 右移 »
技巧
移位运算
- x « 1:算数左移
- 数字的二进制表示的所有位向左移动一位,相当于乘以 2
- 在右边补 0
- x » 1:算数右移
- 数字的二进制表示的所有位向右移动一位,相当于除以 2
- 在左边补符号位,即正数补 0,负数(在补码的基础上)补 1
- 负数移位
- 负数是以补码的形式存储的,负数进行右移运算时需要将其取反转换成反码,加一转换成补码,再将其向右移动一位得到新的补码,再将其减一得到新的反码,再取反转换成原码才能得到结果。例如 -7 的二进制表示是 10000111(因为 32 位太长所以这里用 8 位 int 型表示),其反码是 11111000,补码是11111001,向右移动一位是 11111100,减一得到新的反码 11111011,原码是10000100,也就是 -4;补码向左移一位是 11110010,减一得到新的反码 11110001,原码是 10001110,也就是 -14
- 比较简单的理解方式是左移乘以 2,右移除以 2。例如 -7 » 1 = -7 / 2 = -4,-7 « 1 = -14
- x « 1:算数左移
题目
1. 单个数字
693 交替位二进制数
检查一个二进制数相邻的两个位数是否均不相等。
逐位 & 1 进行判断即可。
class Solution {
public:
bool hasAlternatingBits(int n) {
bool rel = n & 1;
while (n > 0 && (n & 1) == rel) {
rel = !rel;
n >>= 1;
}
return n <= 0;
}
};
476 数字的补数
给一个正整数,求二进制表示取反的结果,取反不包括前导 0。
对每一位异或 1 即可。将大于 num 的第一个 2 ^ n 的数减一即可得到二进制表示全是 1 的,位数等于 num 的位数的数。
class Solution {
public:
int findComplement(int num) {
long long util = 1;
while (util <= num)
util <<= 1;
return num ^ (util - 1);
}
};
461 汉明距离
计算两个整数的二进制表示在各位上不同的数目。
逐位进行异或判断即可。
class Solution {
public:
int hammingDistance(int x, int y) {
int res = 0;
while (x > 0 || y > 0) {
res += ((x & 1) ^ (y & 1));
x >>= 1, y >>= 1;
}
return res;
}
};
762 二进制表示中质数个计算置位
计算 [L, R] 中置位位数为质数的个数。
先逐位判断数 i 在当前位上是否等一 1,得到置位位数后判断是否是质数。判断质数的时候可以先排除掉模以 6 等于 0, 2, 3, 4 的情况,因为这几种情况分别可以被 6, 2, 3, 2 整除,剩下的再判断其模以 6n - 1 和 6n + 1 是否等于 0 即可。还可以先把小于等于 32 的质数存储在哈希表或数组中,这样的话查询时间会降低一些。时间复杂度是 O(n),n 是 [L, R] 的个数。
class Solution {
public:
int countPrimeSetBits(int L, int R) {
int res = 0;
for (int i = L; i <= R; ++i) {
int m = i;
int cnt = 0;
while (m > 0) {
if (m & 1)
++cnt;
m >>= 1;
}
if (IsPrime(cnt))
++res;
}
return res;
}
bool IsPrime(int num) {
if (num < 4)
return num > 1;
else if (num % 6 != 1 && num % 6 != 5)
return false;
for (int i = 5; i <= sqrt(num); i += 6)
if (num % i == 0 || num % (i + 2) == 0)
return false;
return true;
}
};
136 只出现一次的数字
给一个数组,其他数都出现了两次,只有一个数出现了一次,找到这个数。
因为 a ^ a = 0,所以可以用 0 异或这个数组中的所有数,最后得到的就是唯一的一个数。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res = 0;
for (auto &m:nums)
res ^= m;
return res;
}
};