位运算
计算机底层都是用二进制来表示的。每个数都可以表示成二进制的形式,位运算就是基于整数的二进制表示形式来进行的运算,所以运算起来还是很快的。
常用的运算符有6种,分别是 与&
、或|
、异或^
、取反~
、左移<<
、右移>>
。
基础操作
运算符 | 描述 | 解释 |
---|---|---|
& | 与 | 二进制对应位上都是1才是1 |
| | 或 | 二进制对应位上有1就是1 |
^ | 异或 | 二进制对应位上不同才是1 |
~ | 取反 | 0 变 1, 1 变 0 |
<< | 左移 | 各二进位全部左移若干位,高位丢弃,低位补0 |
>> | 右移 | 各二进位全部右移若干位,高位补什么取决于编译器 |
5 = ( 101 ) 2 6 = ( 110 ) 2 5 & 6 = ( 100 ) 2 5 ∣ 6 = ( 111 ) 2 5 ⊕ 6 = ( 011 ) 2 5 = (101)_2 \\ 6 = (110)_2 \\ 5 \& 6 = (100)_2 \\ 5 | 6 = (111)_2 \\ 5 \oplus 6= (011)_2 5=(101)26=(110)25&6=(100)25∣6=(111)25⊕6=(011)2
⊕
\oplus
⊕ 代表异或,计算机里面的符号是 ^
.
一些公式
0 ^ n = n
n ^ n = 0
所以: n ^ m ^ m = n
乘 2 的非负整数次幂
n << m
代表的是
n
∗
(
2
m
)
n*(2^m)
n∗(2m)
除以 2 的非负整数次幂
n >> m
代表的是
n
/
(
2
m
)
n / (2^m)
n/(2m)
交换两个整数
n = n ^ m
m = n ^ m
n = n ^ m
注意顺序不能乱,可以仔细的想一想。
获取一个数二进制的某一位
(n >> m) & 1; // 获取 n 的第 m 位, 最低位的编号为 0
将一个数二进制的某一位设置为 0
n & ~(1 << m); // 将 n 的第 m 位设置为 0 ,最低位编号为 0
将一个数二进制的某一位设置为1
n | (1 << m); // 将 n 的第 m 位设置为 1 ,最低位编号为 0
将一个数二进制的某一位取反
n ^ (1 << m); // 将 n 的第 m 位取反 ,最低位编号为 0
移除二进制表示的最后一个1
n & (n - 1)
所以如果想知道一个数 n 的二进制有多少个 1, 可以这样算。
while(n){
n = n & (n - 1);
ans++;
}
每次都去掉二进制表示的最后一个 1,所以答案就是 ans。
获取二进制表示的最后一个1
(n & (n - 1)) ^ n
例题:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
有一个数的个数超过了数组长度的一半, 所以我们可以按照二进制的每一位来统计答案。
二进制只有 0 和 1, 对于每一位,统计一下0 和 1 出现的次数。如果 1 出现的次数大于一半,那么答案的这一位也是1,否则就是 0.
具体看代码就可以理解。
int majorityElement(vector<int>& nums) {
int ans = 0;
int n = nums.size();
//统计每位数字的第i位二进制
for(int i = 0; i < 32; i++){
int cnt = 0;
for(int j = 0; j < n; j++){
//如果第i位为1, 那么 cnt++.
if((nums[j] >> i & 1) == 1) cnt++;
}
//如果所有数字的二进制数中,第i位1比0多, 把答案的第 i 位变成 1.
if(cnt > n / 2) ans ^= (1 << i);
}
return ans;
}
这个题还有一个不是位运算的解法, 而且非常优雅,感兴趣的同学可以去找一下题解,或者自己再想一想。
例题
请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
就是统计二进制有多少个 1, 我们上面也说了这个技巧,直接拿来用就可以了。
int hammingWeight(uint32_t n) {
int cnt = 0;
while(n){
n = n & (n - 1);
cnt++;
}
return cnt;
}