神奇的位运算
1. 不用临时变量交换两个数
异或运算
- 两个相同的数异或为0 即n ^ n = 0;
- 任何数与0异或为它本身,即n ^ 0 = n。
- 支持交换律、结合律
a = a ^ b # (1)
b = a ^ b # (2)
a = a ^ b # (3)
解释如下:
把(1)中的 a
带入(2)中,则有
b = a ^ b = (a ^ b) ^ b = a ^ (b ^ b) = a ^ 0 = a
同理将(1)、(2)的结果带入(3)中,则有
a = a ^ b = (a ^ b) ^ a = (a ^ a) ^ b = 0 ^ b = b
2. 判断一个数的奇偶性
与运算
- 相同为0,不同为1
判断一个数n是偶数还是奇数,只需要判断n的二进制最后一位是1还是0。是0表示是偶数,是1表示是奇数。
if n & 1 == 1: # n为奇数
3. 乘2/除2
n << 1 # 左移一位,表示乘2
n >> 1 # 右移一位,表示除2
4. 取两个数中的最大值
def max(a, b):
return b & ((a-b) >> 31) | a & (~(a-b) >> 31)
解释如下:
b & ((a-b) >> 31)
其中(a-b) >> 31
表示取(a-b)
的符号位。
当b <= a
时,符号位为0,b & 0 = 0
当b > a
时,符号位为-1。b & -1 = b
即当b > a
时结果为b,否则结果为0。
a & (~(a-b) >> 31)
其中(~(a-b) >> 31)
表示对(a-b)
的符号位取反。
当a >= b
时,取反结果为-1,a & -1 = a
当a < b
时,取反结果为0,a & 0 = 0
即当a >= b
时结果为a,否则结果为0。
- 最后对前两步结果进行
或
运算,因为前两步的结果中一定有一个为0,另一个非0(即最大值)。所以经过或
运算后结果非0(即为最大值)。
5. 取两个数中的最小值
def max(a, b):
return a & ((a-b) >> 31) | b & (~(a-b) >> 31)
6. 取绝对值
def abs(n):
return (n ^ (n >> 31) - (n >> 31))
7. 找出只出现一次的数字
在一组整型数据中,只有一个数字出现了一次,其余数字都出现了两次。找出那个只出现一次的数字。
由异或运算的特性可知:两个相同数字进行异或结果为0;一个数和0异或结果为它本身;且异或支持交换律和结合律。所以只需要对全部的数字进行异或运算,结果就是只出现一次的数字。如l = [1,2,1,0,0]
1 ^ 2 ^ 1 ^ 0 ^ 0 = (1 ^ 1) ^ (0 ^ 0) ^ 2 = 0 ^ 0 ^ 2 = 2
def find_only(l):
tmp = l[0]
for i in range(1, len(l)-1):
tmp ^= l[i]
return tmp
l = [1,2,3,4,4,3,1,0,0]