1. 为什么位运算值得单独学习?
在LeetCode算法题中,位运算往往是最容易被忽视却又最常出奇制胜的技巧。我第一次在周赛中遇到「136. 只出现一次的数字」时,用了哈希表存储出现次数,结果被一位用异或运算的选手以1/3的代码量完爆——这就是位运算的魅力。
位运算的核心优势在于:
- 时间复杂度O(1):无论数据规模多大,位操作都是固定时间完成
- 空间复杂度极低:通常只需要几个临时变量
- 硬件级高效:CPU原生支持位操作,比算术运算快10倍以上
- 代码简洁优雅:复杂逻辑往往能用一行位运算实现
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 必须掌握的六大位操作技巧
2.1 基础运算符深度解析
c复制// C/C++中的位运算符(其他语言类似)
unsigned a = 0b1100, b = 0b1010;
a & b; // AND → 0b1000
a | b; // OR → 0b1110
a ^ b; // XOR → 0b0110
~a; // NOT → 0b0011 (假设4位)
a << 2; // 左移 → 0b110000
a >> 1; // 右移 → 0b0110
特别注意:右移分为逻辑右移(补0)和算术右移(补符号位),C/C++中对于有符号数是实现定义行为,建议用unsigned避免歧义
2.2 高频位操作套路
- 检测第n位是否为1:
x & (1 << n) - 设置第n位为1:
x |= (1 << n) - 清除第n位:
x &= ~(1 << n) - 切换第n位:
x ^= (1 << n) - 保留最低位的1:
x & -x - 清除最低位的1:
x & (x - 1)
2.3 实战案例:191. 位1的个数
python复制def hammingWeight(n):
count = 0
while n:
n &= n - 1 # 清除最低位的1
count += 1
return count
这个解法比逐位检查快得多,时间复杂度仅为O(m),m是1的个数。我在周赛实测中,该解法比bin(n).count('1')快3倍。
3. 位运算的三大进阶应用
3.1 状态压缩技巧
当需要表示一组布尔状态时,可以用整数的每一位代表一个状态。例如解数独时,可以用一个int表示某行已使用的数字:
java复制int rowState = 0;
// 标记数字5已使用
rowState |= 1 << 5;
// 检查数字5是否使用
if ((rowState & (1 << 5)) != 0) {
// 已使用
}
3.2 快速幂算法
计算a^b时,通过二进制分解可以做到O(logb)时间复杂度:
python复制def fastPow(a, b):
res = 1
while b > 0:
if b & 1: # 当前位为1
res *= a
a *= a
b >>= 1
return res
3.3 布隆过滤器原理
利用多个哈希函数和位数组,以极小的空间实现概率型去重。虽然可能有误报,但绝无漏报:
code复制插入元素x:
1. 用k个哈希函数计算h1(x)...hk(x)
2. 将位数组的这些位置1
查询元素y:
若所有h1(y)...hk(y)位置都为1,则可能存在
4. 位运算的边界陷阱与调试技巧
4.1 整数溢出问题
在做左移操作时特别容易忽视。例如判断一个数是否是2的幂:
c++复制bool isPowerOfTwo(int n) {
if (n <= 0) return false; // 必须处理非正数!
return (n & (n - 1)) == 0;
}
4.2 符号位处理
在位运算中,有符号数的右移行为取决于编译器。建议:
- 明确使用unsigned类型
- 需要算术右移时,强制转换为有符号类型
4.3 调试打印技巧
在调试位运算时,我习惯用以下方法可视化:
python复制def print_bits(x, n=32):
print(bin(x & ( (1 << n) - 1 ))[2:].zfill(n))
5. LeetCode位运算经典题型精讲
5.1 只出现一次的数字系列
- 136题:所有数字出现两次,找出唯一出现一次的数 → 全员异或
- 137题:所有数字出现三次 → 统计每位1的个数模3
- 260题:两个唯一数 → 分组异或
5.2 位操作应用题
- 201. 数字范围按位与:找二进制公共前缀
- 371. 两整数之和:用位运算实现加法
- 393. UTF-8验证:位掩码验证
5.3 状态压缩DP
- 526. 优美的排列:用二进制表示已选数字
- 1125. 最小的必要团队:技能集合的或操作
6. 位运算的扩展应用场景
6.1 高性能计算优化
在图像处理中,用位运算加速像素操作:
- 将4个8位颜色通道打包成32位整数
- 用位掩码同时处理多个像素
6.2 游戏开发中的位棋盘
国际象棋AI常用64位整数表示棋盘状态:
- 每个bit代表一个格子是否有棋子
- 走子运算转化为位操作
6.3 网络协议中的标志位
TCP头部中的控制标志就是典型的位域应用:
code复制URG ACK PSH RST SYN FIN
7. 我的位运算刷题路线建议
-
基础阶段(2周):
- 掌握所有位运算符
- 完成LeetCode「位运算」标签下的简单题
-
进阶阶段(3周):
- 理解位掩码概念
- 攻克中等难度状态压缩问题
- 学习布隆过滤器等数据结构
-
高手阶段(持续):
- 在周赛中刻意使用位运算解法
- 研究计算机系统底层中的位操作应用
我个人的错题本记录显示,位运算题的首次通过率只有43%,但掌握后成为我的优势题型。建议准备一个位运算cheatsheet,在解题时多思考:"这个问题能否用位运算优化?"
