LeetCode 190简单位运算
颠倒二进制位 图解题解
这道题到底在问什么
给一个无符号整数(32 位),把它的二进制位前后颠倒后,返回得到的新数。
- 输入
- 00000010100101000001111010011100
- 输出
- 00111001011110000010100101000000
最优解:一步一步想明白
- 3记住这套「取末位 → 放进结果 → 结果左移、原数右移」的三连动作,下面每一帧都在重复它。
- 4第 1 步·取末位:用 n & 1 读出原数现在的最低位(高亮格)= 1。这一位马上要搬到结果的末尾去。
- 5第 1 步·入结果:result 先左移腾出最低位,再把 1 填进去 →「1」。取走的那位用过即丢(原数右移),刚搬的格子变绿。
- 6第 2 步·取末位:用 n & 1 读出原数现在的最低位(高亮格)= 0。这一位马上要搬到结果的末尾去。
- 7第 2 步·入结果:result 先左移腾出最低位,再把 0 填进去 →「10」。取走的那位用过即丢(原数右移),刚搬的格子变绿。
- 8第 3 步·取末位:用 n & 1 读出原数现在的最低位(高亮格)= 0。这一位马上要搬到结果的末尾去。
- 9第 3 步·入结果:result 先左移腾出最低位,再把 0 填进去 →「100」。取走的那位用过即丢(原数右移),刚搬的格子变绿。
- 10第 4 步·取末位:用 n & 1 读出原数现在的最低位(高亮格)= 0。这一位马上要搬到结果的末尾去。
- 11第 4 步·入结果:result 先左移腾出最低位,再把 0 填进去 →「1000」。取走的那位用过即丢(原数右移),刚搬的格子变绿。
- 12第 5 步·取末位:用 n & 1 读出原数现在的最低位(高亮格)= 1。这一位马上要搬到结果的末尾去。
- 13第 5 步·入结果:result 先左移腾出最低位,再把 1 填进去 →「10001」。取走的那位用过即丢(原数右移),刚搬的格子变绿。
- 14第 6 步·取末位:用 n & 1 读出原数现在的最低位(高亮格)= 0。这一位马上要搬到结果的末尾去。
- 15第 6 步·入结果:result 先左移腾出最低位,再把 0 填进去 →「100010」。取走的那位用过即丢(原数右移),刚搬的格子变绿。
- 16第 7 步·取末位:用 n & 1 读出原数现在的最低位(高亮格)= 1。这一位马上要搬到结果的末尾去。
- 17第 7 步·入结果:result 先左移腾出最低位,再把 1 填进去 →「1000101」。取走的那位用过即丢(原数右移),刚搬的格子变绿。
- 18第 8 步·取末位:用 n & 1 读出原数现在的最低位(高亮格)= 0。这一位马上要搬到结果的末尾去。
- 19第 8 步·入结果:result 先左移腾出最低位,再把 0 填进去 →「10001010」。取走的那位用过即丢(原数右移),刚搬的格子变绿。
- 20第 9 步·取末位:用 n & 1 读出原数现在的最低位(高亮格)= 0。这一位马上要搬到结果的末尾去。
- 21第 9 步·入结果:result 先左移腾出最低位,再把 0 填进去 →「100010100」。取走的那位用过即丢(原数右移),刚搬的格子变绿。
- 22第 10 步·取末位:用 n & 1 读出原数现在的最低位(高亮格)= 1。这一位马上要搬到结果的末尾去。
- 23第 10 步·入结果:result 先左移腾出最低位,再把 1 填进去 →「1000101001」。取走的那位用过即丢(原数右移),刚搬的格子变绿。
- 24第 11 步·取末位:用 n & 1 读出原数现在的最低位(高亮格)= 0。这一位马上要搬到结果的末尾去。
- 25第 11 步·入结果:result 先左移腾出最低位,再把 0 填进去 →「10001010010」。取走的那位用过即丢(原数右移),刚搬的格子变绿。
- 26第 12 步·取末位:用 n & 1 读出原数现在的最低位(高亮格)= 0。这一位马上要搬到结果的末尾去。
- 27最后一位:搬入原数最高位 0,落在结果最低位;而第 1 步搬的位早被左移顶到了最高位——顺序彻底倒了过来。
- 2812 位全部搬完,原数清空、结果定格为 100010100100。验证:把原数 001001010001 倒着读一遍 = 100010100100,与结果完全一致。32 位只是把循环从 12 次改成 32 次,逻辑一模一样。
⚠️ 容易写错的地方
✗ 错:Java 用 n >>= 1(带符号右移)
✓ 对:n >>>= 1(无符号右移)
带符号右移会用符号位(1)补高位,负数会越移越乱;无符号右移补 0 才对
✗ 错:先右移 n 再取位
✓ 对:先 n & 1 取位,再 n >>= 1
顺序反了会丢掉最低位、整体错位
✗ 错:result = result | (n & 1) 不左移
✓ 对:result = (result << 1) | (n & 1)
不左移所有位会挤在最低位、互相覆盖,必须先腾位
完整代码(Python / C++ / Java)
Python
def reverseBits(self, n: int) -> int:
result = 0
for _ in range(32): # 32 位固定循环
result = (result << 1) | (n & 1) # 结果左移 + 取原数末位
n >>= 1 # 原数右移,丢掉末位
return resultC++
uint32_t reverseBits(uint32_t n) {
uint32_t result = 0;
for (int i = 0; i < 32; i++) { // 32 位固定循环
result = (result << 1) | (n & 1); // 左移 + 取末位
n >>= 1; // 原数右移
}
return result;
}Java
public int reverseBits(int n) {
int result = 0;
for (int i = 0; i < 32; i++) { // 32 位固定循环
result = (result << 1) | (n & 1); // 左移 + 取末位
n >>>= 1; // 无符号右移,丢末位
}
return result;
}复杂度
时间
O(1)
固定循环 32 次,与输入大小无关
空间
O(1)
只用 result 一个变量
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 颠倒二进制位 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么取原数末位用 n & 1?+
二进制里最低位就是「个位」,n & 1 把除最低位外全部清零,只留下最低位的值(0 或 1)。这是取末位的标准位运算技巧。
能不能不循环、用分治更快?+
可以。分治法把 32 位按 16/8/4/2/1 逐层两两交换(先交换前后 16 位、再 8 位…),用固定几条掩码与移位,O(1) 内只需 5 步。逐位法更直观,分治法更快,面试讲清逐位即可、能提分治是加分。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 颠倒二进制位 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。