这里想记录一些在做题过程中遇到的位运算相关技巧。
在位运算相关的题目中,有很多会与位 1 的个数相关。这里有个相关的小技巧。
n & (n-1)
通过以上表达式可以将 n
二进制表示的最低位 1 移除。原理是最低位1后会跟一些0。即 , 将他减一后,得到 这两数相与便可以将最后一位 1 移除,而其他位 1 不受影响。
这个技巧可以运用在很多地方,比如我们想统计数n
中1
的数量。
可以直接让n
与n-1
相与,直到n=0
。代码如下:
while (n) { n &= n - 1; ret++; }
利用
(n&(-n))==n
可以用来判断正整数n
是否是2的幂,利用计算机补码知识,可以知道-n
即为n
所有位取反加一,记最后一位 1 前的高位为 (n
为2的幂时全为0),n
即 ,而 -n
为 ,即 ,所以当n
为2的幂时, n
和 -n
相与后仍然得到 n
。
在进行位运算时,要时刻注意位运算优先级较低,以上面判断是否是2的幂为例,应该使用
(n&(-n))==n
而不是
n&(-n)==n
后者会先运算 (-n)==n
。
附上c++运算符优先级表:
优先级 | 运算符 | 类 | 结合性 |
---|---|---|---|
1 | ( ) | 括号运算符 | 由左至右 |
1 | [ ] | 方括号运算符 | 由左至右 |
2 | !、 +(正号)、 - (负号) | 一元运算符 | 由右至左 |
2 | ~ | 位逻辑运算符 | 由右至左 |
2 | ++、– | 递增与递减运算符 | 由右至左 |
3 | *、/、% | 算术运算符 | 由左至右 |
4 | +、- | 算术运算符 | 由左至右 |
5 | <<、>> | 位左移、位右移运算符 | 由左至右 |
6 | >、>=、<、<= | 关系运算符 | 由左至右 |
7 | ==、!= | 关系运算符 | 由左至右 |
8 | &(位运算符AND) | 位逻辑运算符 | 由左至右 |
9 | ^(位运算负号XOR) | 位逻辑运算符 | 由左至右 |
10 | | (位运算负号OR) | 位逻辑运算符 | 由左至右 |
11 | && | 逻辑运算符 | 由左至右 |
12 | || | 逻辑运算符 | 由左至右 |
13 | ?: | 条件运算符 | 由右至左 |
14 | = | 赋值运算符 | 由右至左 |