算法基础|位运算

常见的位运算包括:

1. 按位与(&):对两个二进制数的每一位进行逻辑与运算。只有当对应位都是1时,结果才为1,否则为0。

示例:5 & 3 等价于 0101 & 0011,结果是 0001,即 1

2。 按位或( | ):对两个二进制数的每一位进行逻辑或运算。只要有一个对应位是1,结果就是1。

示例:5 | 3 等价于 0101 | 0011,结果是 0111,即 7

3. 按位异或(^):对两个二进制数的每一位进行异或运算。当对应位不同时,结果为1;相同时,结果为0。

示例:5 ^ 3 等价于 0101 ^ 0011,结果是 0110,即 6

Takeaway: 0 和 任意数做异或运算都等于这个数自身;1 和 任意数做异或运算,结果是将这个数每个二进制位上的数字反转过来。

以上运算也被称作是双目运算,即把两个整数作为二进制数,对这两个数的每个数位逐一进行相应运算

4. 左移(<<):将二进制数的每一位向左移动指定的位数,右边用0填充。

示例:5 << 1 等价于 0101 << 1,结果是 1010,即 10

5. 右移(>>):将二进制数的每一位向右移动指定的位数,左边用0(对于无符号数)或符号位(对于有符号数)填充。

示例:5 >> 1 等价于 0101 >> 1,结果是 0010,即 2

6. 取反 (~):对二进制数的每个二进位取反,使数字 11 变为 00,00 变为 11

这些运算在低级编程和性能优化中非常有用,因为它们直接操作二进制位,执行速度通常比其他类型的运算快。

应用1 - 判断整数奇偶

一个整数,只要是偶数,其对应二进制数的末尾一定为 0 (0 * 2^0);只要是奇数,其对应二进制数的末尾一定为 1 (1 * 2 ^0)。所以,我们通过与 1 进行按位与运算,即可判断某个数是奇数还是偶数。

(x & 1) == 1 # 奇数,因为 x 最后一位是 1
(x & 1) == 0 # 偶数,因为 x 最后一位是 0 

应用2 - 二进制数选取指定位

如果我们想要从一个二进制数 X 中取出某几位,使取出位置上的二进位保留原值,其余位置为 0,则可以使用另一个二进制数 Y,使该二进制数上对应取出位置为 1,其余位置为 0 (不管这个位置原先是什么数字,都会变成0)。然后令两个数进行按位与运算(X & Y),即可得到想要的数。

举个例子,比如我们要取二进制数 X=01101010​ 的末尾 4 位,则只需将 X=01101010 与 Y=00001111​ (末尾 4 位为 1,其余位为 0) 进行按位与运算,即 01101010 & 00001111 == 00001010。其结果 00001010 就是我们想要的数(即二进制数 01101010 的末尾 4 位)。

应用3 - 反转指定位

如果我们想要把一个二进制数 X 的某几位进行反转,则可以使用另一个二进制数 Y,使得该二进制上对应选取位置为 1,其余位置为 0。然后令两个数进行按位异或运算(X ^ Y),即可得到想要的数。

举个例子,比如想要将二进制数 X=01101010 的末尾 4 位进行反转,则只需将 X=01101010​ 与 Y=00001111(末尾 4 位为 1,其余位为 0)进行按位异或运算,即 01101010 ^ 00001111 = 01100101。其结果 01100101 就是我们想要的数(即将二进制数 X=01101010 的末尾 4 位进行反转)。

(因为对于XOR来说,1 ^ 1 = 0, 0 ^ 1 = 1, 刚好起到反转的效果)

应用4 - 交换两个数(只能交换两个数)

实际上也是利用了应用3

a, b = 01010, 10100
a ^= b  # a = a ^ b = 11110 相当于省去一个临时变量,利用负负得正
b ^= a  # b = b ^ a = 01010
a ^= b  # a = a ^ b = 10100

应用5 - 将二进制最右侧为 1 的二进位改为 0 

通过 X & (X-1) 即可完成

比如 X=01101100​,X−1=01101011​,则 X & (X - 1) == 01101100 & 01101011 == 01101000,结果为 01101000​(即将 X 最右侧为 1 的二进制为改为 0)

应用6 - 计算二进制中二进位为 1 的个数 

利用应用5的性质,因为一次的X & (X-1)可以把最右侧的 1 改为 0,那么可以多次操作,直到 X全部变成 0,并记录下操作的次数

应用7 - 判断一个数是否为 2 的次方

通过判断 X & (X - 1) == 0 是否成立,即可判断 X 是否为 2 的幂次方。

这是因为:

  1. 凡是 2 的幂次方,其二进制数的某一高位为 1,并且仅此高位为 1,其余位都为 0。比如:4(10)=00000100(2)、8(10)=00001000(2)。
  2. 不是 2 的幂次方,其二进制数存在多个值为 1 的位。比如:510=00000101(2)​、610=00000110(2)​。

接下来我们使用 X & (X - 1) 操作,将原数对应二进制数最右侧为 1 的二进位改为 0 之后,得到新值:

  1. 如果原数是 2 的幂次方,则通过 X & (X - 1) 操作之后,新值所有位都为 0,值为 0。
  2. 如果该数不是 2 的幂次方,则通过 X & (X - 1) 操作之后,新值仍存在不为 0 的位,值肯定不为 0。

所以我们可以通过是否为 0 即可判断该数是否为 2 的幂次方。

应用8 - 用位运算实现快速乘 2 和 除 2 操作

乘2:y << 1  -> y 代表的二进制数集体向左移动一位

除2(向下取整):  y >> 1   -> y 代表的二进制数集体向右移动一位

参考资料:01. 位运算知识 | 算法通关手册(LeetCode)

  • 13
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值