1.基本位运算符
- 或:如果两个值有一个为1,或结果为1,否则为0;
- 与:如果两个值都为1,与结果为1,否则为0;
- 异或:如果两个值不同,异或结果为1,否则为0;
2.经典应用
2.1 原地交换两个int变量
- 可以通过相加来实现:
int a = 3, b = 4;
a = a + b;
b = a - b;
a = a - b;
- 用异或来实现:
int x = 3, y = 4;
x = x ^ y;
y = x ^ y;
x = x ^ y;
异或运算支持运算的交换律和结合律。
y = x ^ y = (x ^ y) ^ y = x ^ (y ^ y) = x ^ 0 = x
:x 的值成功赋给y。
x = x ^ y = (x ^ y) ^x = ( x ^ x) ^ y = 0 ^ y = y
,同理y的值成功赋给x。
2.2 整数的二进制表达式中有多少个1
x & (x - 1)
代表将x的二进制表达中最右边的1变为0。- 求二进制1的个数模板:
while(x) {
x = x & (x - 1);
ans++;
}
- 原理:把一个整数减去一,再和原来的整数做相与运算,会把最右边的1变为0,根据上述思想,二进制x中有多少个1,就要进行多少次相与的运算,例如 x=9;
第一步: 第二步:
1 0 0 1 1 0 0 0
& 1 0 0 0 & 0 1 1 1
———————————— ————————————
1 0 0 0 0 0 0 0
2.3 在其它数都出现偶数次的数组中找出两个出现一次的数
- 解析:如果把数组所有的数字都依次异或之后,则可以消掉成对出现的次数,还有2个是单一的,异或值不为0,表现在二进制中肯定有一位是1,那么这两个数字在该位肯定有一个为1,一个为0。
- 核心代码:
vector<int> FindNumsAppearOnce(vector<int>& array) {
int sum = 0;
for (auto arr : array) {
sum = sum ^ arr;
}
int x = 0, y = 0, count = 0;
while ((sum & 1) == 0) {
count++;
sum = sum >> 1;
}
for (auto arr : array) {
if ((arr >> count) & 1) {
x = x ^ arr;
} else {
y = y ^ arr;
}
}
return {min(x, y), max(x, y)};
}
2.4 在其它数都出现K次的数组中找出出现一次的数
- 核心代码:
int foundOnceNumber(vector<int>& arr, int k) {
int res = 0;
for (int i = 0; i < 32; i++) {
int sum = 0;
for (int j = 0; j < arr.size(); j++) {
sum += (arr[j] >> i) & 1;
}
if (sum % k > 0) {
res = res | (1 << i);
}
}
return res;
}