常用位运算

左移(1 << x)

左移操作的结果是将二进制数的每一位都向左移动指定的位数,右边空出的位用 0 填充。左移操作相当于将原始数乘以 2 的 x 次幂。


右移 (x >> 1)

表达式 x >> 1 是右移操作,用于将整数 x 的二进制表示向右移动一位。右移操作可以用于快速将整数除以 2 的幂次方,因为右移一位相当于除以 2。


与(&)

如果两个位都是 1,与的结果为 1。
如果两个位中至少有一个为 0,与的结果为 0。


提取或修改一个数的特定位。 mask & (1 << i)

掩码生成:与操作常用于生成位掩码,用于提取或修改一个数的特定位。
提取mask中下标(从右往左数 0 - n)第 i 下标的数字是0还是1

提取或修改一个数的特定位。 mask >> (i - 1) & 1

i 从0 开始
掩码生成:与操作常用于生成位掩码,用于提取或修改一个数的特定位。
用于提取 mask 中的第 i - 1 下标的值,而不是第 i 下标的值。
和mask & (1 << (i - 1))一样。




提取整数 a(二进制)最右侧(最低位)的 1 所在的位

表达式 a& (-a) 可以用于提取整数 a最右侧(最低位)的 1 所在的位,将其他位清零。这个操作通常用于查找二进制中最右侧的 1 所在的位置,也就是最低有效位(LSB,Least Significant Bit)。

原理
a & (-a) 可以获得a最低的非0位 比如a的二进制原码是 0000 1010,这里最低非0位是bit 1(从右往左第2位)

-a在二进制中的表示是补码(2’s complement code)形式,即先按位取反再加1

取反得 1111 0101(即1's complement code,反码)
加1得 1111 0110(即2's complement code,补码)

原码(0000 1010) 与 补码(1111 0110) 做与运算(&),得 0000 0010,即原码 0000 1010的LSB

更详细的解释:

我们从右向左看发生了什么:

原码最低非0位右边所有的0,经由取反后全部变为1,反码+1会导致这些1逐位发生进位并变为0,最终进位记到最低非0位
原最低非0位是1,取反后是0,进位到这一位0变成1,不再向左进位
原最低非0位左边的每一位经由取反后 和 原码 进行与运算必为0



异或(^)

如果两个位不同,异或的结果为 1。
如果两个位相同,异或的结果为 0。

任何数和 0做异或运算,结果仍然是原来的数,即 a⊕0=a
任何数和其自身做异或运算,结果是 0,即 a⊕a=0
异或运算满足交换律和结合律,即 a⊕b⊕a=b⊕a⊕a=b⊕(a⊕a)=b⊕0=b


交换两个数字

int a = 5, b = 7;
a = a ^ b;
b = a ^ b;
a = a ^ b;

消除重复的数字(只有偶次重复才能用)

通过将数组中的所有数进行异或操作,重复出现的数会相互抵消,最终剩下的数就是单独出现的数。

假设数组中有 2m+1个数,其中有 m个数各出现两次,一个数出现一次。令 a1、a2、…、am为出现两次的 m个数,am+1为出现一次的数。根据交换律和结合律,数组中的全部元素的异或运算结果总是可以写成如下形式:(a1⊕a1)⊕(a2⊕a2)⊕⋯⊕(am⊕am)⊕am+1 = am+1

查找缺失的数字

在一个任选n (0-n) 个不同数的数组中,其中一个数丢失了,数组 nums 中有 n 个数,在这 n 个数的后面添加从 0 到 n 的每个整数,则添加了 n+1个整数,共有 2n+1个整数。

在 2n+1个整数中,丢失的数字只在后面 n+1个整数中出现一次,其余的数字在前面 n 个整数中(即数组中)和后面 n+1个整数中各出现一次,即其余的数字都出现了两次。因此对上述 2n+1个整数进行按位异或运算,结果即为丢失的数字。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值