加载中…
应用场景:快速幂 · 状压 DP · 去重
交互式动画演示,可调整参数并单步执行。
全屏打开graph LR A[位运算] --> B[与或非异或] A --> C[移位] B --> D[去最低位/判奇偶/交换] C --> E[乘除以2/取位]
位运算直接操作二进制位,是计算机最底层的运算方式。在算法面试中,位运算题目考查:
掌握 6~8 个核心技巧,就能覆盖 90% 的位运算面试题。
| 运算 | 符号 | 示例(Java) | 结果 |
|---|---|---|---|
| 与 AND | & | 5 & 3 → 101 & 011 | 001 = 1 |
| 或 OR | | | 5 | 3 → 101 | 011 | 111 = 7 |
| 异或 XOR | ^ | 5 ^ 3 → 101 ^ 011 | 110 = 6 |
| 取反 NOT | ~ | ~5 | -6 |
| 左移 | << | 1 << 3 | 8 |
| 右移 | >> | 8 >> 2 | 2 |
| 无符号右移 | >>> | -1 >>> 28 | 15 |
a ^ a = 0 // 自身异或为 0
a ^ 0 = a // 与 0 异或不变
a ^ b = b ^ a // 交换律
(a ^ b) ^ c = a ^ (b ^ c) // 结合律
异或是位运算题的绝对核心——"出现两次就消掉"。
// n & 1 == 0 → 偶数;n & 1 == 1 → 奇数
boolean isOdd = (n & 1) == 1;int doubled = n << 1; // n * 2
int halved = n >> 1; // n / 2(向下取整)
int times8 = n << 3; // n * 8int lowbit = n & (-n); // 等价于 n & (~n + 1)应用:树状数组(BIT)的核心操作。
n = n & (n - 1); // 清除最右边的 1应用:统计二进制中 1 的个数(Brian Kernighan 算法)。
public int hammingWeight(int n) {
int count = 0;
while (n != 0) {
n &= (n - 1);
count++;
}
return count;
}boolean isPowerOfTwo = n > 0 && (n & (n - 1)) == 0;原理:2 的幂的二进制只有一个 1。
a ^= b;
b ^= a;
a ^= b;面试中了解即可,工程中不推荐(可读性差,且对同一变量/同一数组下标做 XOR 交换会清零)。
问题:数组中只有一个元素出现一次,其余出现两次。找出它。
public int singleNumber(int[] nums) {
int xor = 0;
for (int num : nums) xor ^= num;
return xor;
}问题:其余元素出现三次,找一个出现一次的。
public int singleNumber(int[] nums) {
int ones = 0, twos = 0;
for (int num : nums) {
ones = (ones ^ num) & ~twos;
twos = (twos ^ num) & ~ones;
}
return ones;
}问题:恰好两个元素各出现一次,其余出现两次。
public int[] singleNumber(int[] nums) {
int xorAll = 0;
for (int num : nums) xorAll ^= num;
// 取最低位的 1,将数组分成两组
int diff = xorAll & (-xorAll);
int a = 0, b = 0;
for (int num : nums) {
if ((num & diff) == 0) a ^= num;
else b ^= num;
}
return new int[]{a, b};
}xorAll 中为 1 的位说明两个答案在该位不同,据此分组。问题:[0, n] 中缺了一个数,找出来。
public int missingNumber(int[] nums) {
int xor = nums.length;
for (int i = 0; i < nums.length; i++) {
xor ^= i ^ nums[i];
}
return xor;
}// 方法一:Brian Kernighan
public int hammingWeight(int n) {
int count = 0;
while (n != 0) { n &= (n - 1); count++; }
return count;
}
// 方法二:逐位检查
public int hammingWeight2(int n) {
int count = 0;
for (int i = 0; i < 32; i++) {
count += (n >> i) & 1;
}
return count;
}用整数的每一位表示一个布尔状态,常用于状态压缩 DP 和集合操作:
int mask = 0;
mask |= (1 << i); // 加入第 i 个元素
mask &= ~(1 << i); // 移除第 i 个元素
boolean has = (mask & (1 << i)) != 0; // 检查第 i 个
mask ^= (1 << i); // 切换第 i 个元素应用:
for (int sub = mask; sub > 0; sub = (sub - 1) & mask)| 问题 | 说明 |
|---|---|
| int 是 32 位有符号 | 最高位是符号位 |
>> vs >>> | >> 保留符号,>>> 补 0 |
| 负数的补码 | -n = ~n + 1 |
| 溢出 | 1 << 31 是 Integer.MIN_VALUE |
Integer.toBinaryString(n) 观察位模式。>>> 避免死循环。Integer.MIN_VALUE 取反加一仍为自身(溢出)。