一、取出第 x 位的值(0 / 1)
公式 :(n >> x) & 1
功能:获取数字 n 二进制第 x 位,结果只能是 0 或 1
原理拆解
-
n >> x:将二进制整体右移 x 位,把第 x 位移到最右侧第0位 -
& 1:只保留最低位,清空所有高位,最终得到目标位数值
实战案例
n = 11(二进制 1011)
-
(11 >> 2) & 1→ 取出第2位 → 结果 0 -
(11 >> 3) & 1→ 取出第3位 → 结果 1
避坑重点
这里用有符号右移 >>完全没问题!
因为最后 &1 会截断所有高位,哪怕负数右移补1,也不会影响最终结果。
只有 循环整体右移遍历 时,才需要无符号右移 >>>。
二、将第 x 位 设置为 1
公式 :n = n | (1 << x)
功能 :强制把第 x 位改成1,其他所有位保持不变
原理拆解
-
1 << x:生成掩码,仅第x位为1,其余全0 -
|按位或:有1则1,0不变
实战案例
n = 11(1011),将第2位置1
11 | (1 << 2) = 1011 | 0100 = 1111(十进制15)
若该位原本就是1,运算后数值不变,无副作用。
三、将第 x 位 设置为 0
公式 :n = n & ~(1 << x)
功能 :强制把第 x 位清零,其他所有位保持不变
原理拆解
-
1 << x:生成单1掩码 -
~按位取反:掩码第x位变0,其余全部变1 -
& 按位与:遇0清零、遇1不变,精准清空目标位
实战案例
n = 15(1111),将第3位置0
15 & ~(1 << 3) = 1111 & 0111 = 0111(十进制7)
四、消除最低位的 1(汉明重量核心)
公式 :n = n &(n - 1)
功能 :消去二进制最右侧的一个1,其余位不变
核心用途:统计二进制中1的个数(汉明重量最优解)
实战案例
n = 11(1011)
-
11 & 10 = 1010:消去最后一个1 -
10 & 9 = 1000:再消去最后一个1 -
8 & 7 = 0000:最后一个1消除完毕
循环次数 = 二进制中1的个数,时间复杂度最优。
五、保留最低位的 1(lowbit 核心)
公式 :n & -n
功能 :只保留二进制最右侧的一个1,其余全部清零
底层原理 :计算机负数以补码存储,-n = ~n + 1
实战案例
-
n = 11(1011) →
11 & -11 = 1 -
n = 12(1100) →
12 & -12 = 4
高频应用场景
-
树状数组 lowbit 操作
-
判断数字是否为2的幂:
n > 0 && (n == (n & -n))
六、异或(^)三大核心运算律(算法必考)
异或规则:相同为0,不同为1,是「唯一数字、汉明距离」等题目的核心底层逻辑。
所有高阶异或算法,全部基于以下三条定律,必须熟记!
1. 归零律:a ^ a = 0
任意两个相同的数字异或,结果一定为0。
案例:2 ^ 2 = 0、15 ^ 15 = 0
刷题作用:数组中出现两次的数字,全部异或抵消清零。
2. 恒等律:a ^ 0 = a
任意数字和0 异或,结果等于自身。
案例:0 ^ 4 = 4、0 ^ 99 = 99
刷题作用:初始化结果为0,不会改变第一个运算数的值。
3. 交换律 + 结合律
a ^ b ^ c = a ^ (b ^ c) = (a ^ c) ^ b
核心:异或运算顺序无关,随便调换位置结果不变
经典推导:a ^ b ^ a = (a ^ a) ^ b = 0 ^ b = b
刷题作用:完美解决「其余元素出现两次,一个元素只出现一次」的题目。
真题完整演示(透彻理解)
题目:nums = 4,1,2,1,2
整体运算:0 ^ 4 ^ 1 ^ 2 ^ 1 ^ 2
利用运算律重排:0 ^ 4 ^ (1^1) ^ (2^2)
代入定律:0 ^ 4 ^ 0 ^ 0 = 4
最终得到唯一出现一次的数字,线性时间、常量空间,完美符合题目要求。
七、5大公式终极汇总表(直接背诵)
| 运算功能 | 核心公式 |
|---|---|
| 取出第x位(0/1) | (n >> x) & 1 |
| 第x位置1 | `n |
| 第x位置0 | n & ~(1 << x) |
| 消除最低位1 | n & (n - 1) |
| 保留最低位1(lowbit) | n & -n |
八、配套经典刷题模板(可直接运行)
1. 汉明重量(统计1的个数)
java
public int hammingWeight(int n) {
int count = 0;
while(n != 0){
n = n & (n - 1);
count++;
}
return count;
}
2. 汉明距离(两数二进制不同位数量)
java
public int hammingDistance(int x, int y) {
int xor = x ^ y;
int count = 0;
while(xor != 0){
xor = xor & (xor - 1);
count++;
}
return count;
}
八、终极避坑总结
-
(n>>x)&1无需区分正负,永远正确 -
循环遍历二进制位**
>>>** 负数必须用 无符号右移 -
n&(n-1)消1,n&-n留1,两个极易混淆,务必区分 -
所有位操作位编号默认从0开始,题目从1开始需手动减1