学习链接:04.05.01 位运算(第 13 ~ 14 天) (datawhalechina.github.io)
一、六种位运算规则
运算符 | 描述 | 规则 |
---|---|---|
| | 按位或运算符 | 只要对应的两个二进位有一个为 1 时,结果位就为 1。 |
& | 按位与运算符 | 只有对应的两个二进位都为 1 时,结果位才为 1。 |
<< | 左移运算符 | 将二进制数的各个二进位全部左移若干位。<< 右侧数字指定了移动位数,高位丢弃,低位补 0。 |
>> | 右移运算符 | 对二进制数的各个二进位全部右移若干位。>> 右侧数字指定了移动位数,低位丢弃,高位补 0。 |
^ | 按位异或运算符 | 对应的两个二进位相异时,结果位为 1,二进位相同时则结果位为 0。 |
~ | 取反运算符 | 对二进制数的每个二进位取反,使数字 1 变为 0,0 变为 1。 |
二、
学习位运算的常用操作总结
功 能 | 位运算 | 示例 |
---|---|---|
从右边开始,把最后一个 1 改写成 0 | x & (x - 1) | 100101000 -> 100100000 |
去掉右边起第一个 1 的左边 | x & (x ^ (x - 1)) 或 x & (-x) | 100101000 -> 1000 |
去掉最后一位 | x >> 1 | 101101 -> 10110 |
取右数第 k 位 | x >> (k - 1) & 1 | 1101101 -> 1, k = 4 |
取末尾 3 位 | x & 7 | 1101101 -> 101 |
取末尾 k 位 | x & 15 | 1101101 -> 1101, k = 4 |
只保留右边连续的 1 | (x ^ (x + 1)) >> 1 | 100101111 -> 1111 |
右数第 k 位取反 | x ^ (1 << (k - 1)) | 101001 -> 101101, k = 3 |
在最后加一个 0 | x << 1 | 101101 -> 1011010 |
在最后加一个 1 | (x << 1) + 1 | 101101 -> 1011011 |
把右数第 k 位变成 0 | x & ~(1 << (k - 1)) | 101101 -> 101001, k = 3 |
把右数第 k 位变成 1 | x | (1 << (k - 1)) | 101001 -> 101101, k = 3 |
把右边起第一个 0 变成 1 | x | (x + 1) | 100101111 -> 100111111 |
把右边连续的 0 变成 1 | x | (x - 1) | 11011000 -> 11011111 |
把右边连续的 1 变成 0 | x & (x + 1) | 100101111 -> 100100000 |
把最后一位变成 0 | x | 1 - 1 | 101101 -> 101100 |
把最后一位变成 1 | x | 1 | 101100 -> 101101 |
把末尾 k 位变成 1 | x | (1 << k - 1) | 101001 -> 101111, k = 4 |
最后一位取反 | x ^ 1 | 101101 -> 101100 |
末尾 k 位取反 | x ^ (1 << k - 1) | 101001 -> 100110, k = 4 |
例题:
给你两个整数 left
和 right
,表示区间 [left, right]
,返回此区间内所有数字 按位与 的结果(包含 left
、right
端点)。
思路:
- 按位与操作的特点是,如果某一位在区间内存在 0 和 1 的情况,那么这一位最终的结果就是 0 。
- 为了找到最终结果,我们从高位开始比较
left
和right
。 - 只要
left
小于right
,就将它们右移一位,同时记录移动的位数(shift
)。 - 当
left
不再小于right
时,说明找到了第一个不同的位。 - 此时,将相同的高位部分(即
left
)左移shift
位,得到的就是最终的结果。
class Solution(object):
def rangeBitwiseAnd(self, left, right):
"""
:type left: int
:type right: int
:rtype: int
"""
# 从高位开始逐位比较
shift = 0
while left < right: # 找到第一个不同的位
left >>= 1
right >>= 1
shift += 1
# 把相同的高位部分还原
res = left << shift
return res