LeetCode 7中等位运算
整数反转 图解题解
这道题到底在问什么
给你一个 32 位有符号整数 x,返回把 x 中的每一位数字反转后的结果。如果反转后的数超出了 32 位有符号整数范围 [−2³¹, 2³¹−1],就返回 0。
- 输入
- x = 123456789
- 输出
- 987654321(每一位倒过来,没有超范围)
最优解:一步一步想明白
- 3记住这个变量:rev 是「已经反转出来的部分」。每取一位就 rev = rev×10 + 这位,并顺手检查会不会溢出。下面每一帧都在套它。
- 4开始前:反转结果 rev = 0。我们要从最右边的个位开始,一位位地取出来接到 rev 后面。
- 5指针走到这一位,值是 9(高亮的就是它)。这是最右边的个位。
- 6把 9 接到 rev 末尾:rev 变成 9。再确认它没超过 32 位上限 2147483647,安全,继续取下一位。
- 7指针走到这一位,值是 8(高亮的就是它)。右边变灰的几位是已经接过的。
- 8把 8 接到 rev 末尾:rev 变成 98。再确认它没超过 32 位上限 2147483647,安全,继续取下一位。
- 9指针走到这一位,值是 7(高亮的就是它)。右边变灰的几位是已经接过的。
- 10把 7 接到 rev 末尾:rev 变成 987。再确认它没超过 32 位上限 2147483647,安全,继续取下一位。
- 11指针走到这一位,值是 6(高亮的就是它)。右边变灰的几位是已经接过的。
- 12把 6 接到 rev 末尾:rev 变成 9876。再确认它没超过 32 位上限 2147483647,安全,继续取下一位。
- 13指针走到这一位,值是 5(高亮的就是它)。右边变灰的几位是已经接过的。
- 14把 5 接到 rev 末尾:rev 变成 98765。再确认它没超过 32 位上限 2147483647,安全,继续取下一位。
- 15指针走到这一位,值是 4(高亮的就是它)。右边变灰的几位是已经接过的。
- 16把 4 接到 rev 末尾:rev 变成 987654。再确认它没超过 32 位上限 2147483647,安全,继续取下一位。
- 17指针走到这一位,值是 3(高亮的就是它)。右边变灰的几位是已经接过的。
- 18把 3 接到 rev 末尾:rev 变成 9876543。再确认它没超过 32 位上限 2147483647,安全,继续取下一位。
- 19指针走到这一位,值是 2(高亮的就是它)。右边变灰的几位是已经接过的。
- 20把 2 接到 rev 末尾:rev 变成 98765432。再确认它没超过 32 位上限 2147483647,安全,继续取下一位。
- 21指针走到这一位,值是 1(高亮的就是它)。右边变灰的几位是已经接过的。
- 22把 1 接到 rev 末尾:rev 变成 987654321。再确认它没超过 32 位上限 2147483647,安全,继续取下一位。
- 23每一位都取过、接过了(整排变灰)。反转后的结果就是 rev = 987654321,全程没超范围,直接返回它。
⚠️ 容易写错的地方
✗ 错:反转后才判溢出
✓ 对:每接一位前/后就检查 rev 是否越界
在 32 位整数里反转过程中就可能溢出,等结果出来再判已经晚了(值已被截断)
✗ 错:忘了处理负号
✓ 对:先记下正负、对绝对值反转,最后还原符号
−123 应反转成 −321,符号不能丢
✗ 错:末尾有 0 时多此一举地补 0
✓ 对:rev×10+d 自然丢掉前导零
如 120 反转成 21(不是 021),按位接末尾会自动正确,不用特判
完整代码(Python / C++ / Java)
Python
def reverse(x):
INT_MAX = 2**31 - 1 # 32 位上限
INT_MIN = -2**31 # 32 位下限
sign = 1 if x >= 0 else -1 # 记下正负
x = abs(x)
rev = 0
while x: # 逐位取最低位
d = x % 10 # 取个位
x //= 10
rev = rev * 10 + d # 接到末尾
rev *= sign
if rev < INT_MIN or rev > INT_MAX: # 溢出判 0
return 0
return revC++
int reverse(int x){
long rev = 0; // 用更大类型防溢出
while (x != 0) {
rev = rev * 10 + x % 10; // 取个位接末尾
x /= 10;
if (rev > INT_MAX || rev < INT_MIN) return 0;
}
return (int)rev;
}Java
public int reverse(int x) {
long rev = 0; // 用 long 防溢出
while (x != 0) {
rev = rev * 10 + x % 10; // 取个位接末尾
x /= 10;
if (rev > Integer.MAX_VALUE || rev < Integer.MIN_VALUE)
return 0;
}
return (int) rev;
}复杂度
时间
O(log|x|)
循环次数等于 x 的位数,每位只处理一次
空间
O(1)
只用 rev 一个变量,不开额外数组
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 整数反转 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
rev 这个变量代表什么?+
rev 是「已经反转出来的部分」,从 0 起步。每取一位数字 d 就 rev = rev×10 + d,把它接到末尾,处理完所有位 rev 就是答案。
负数怎么处理?+
先记下符号、对绝对值做反转,最后把符号乘回去。比如 −123 → 反转 123 得 321 → 还原成 −321。
为什么数字末尾的 0 不用特殊处理?+
按位接末尾时(rev×10+d),前导的 0 会被自然吃掉。比如 120 反转:取 0→rev=0,取 2→rev=2,取 1→rev=21,结果就是 21。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 整数反转 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。