LeetCode #7 Medium
题目描述
给你一个 32 位的有符号整数 x,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−2^31, 2^31 − 1],就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
示例
输入:x = 123
输出:321
输入:x = -123
输出:-321
输入:x = 120
输出:21
思路分析
方法一:字符串反转法(直观但非最优)
最直观的想法是将数字转为字符串,反转后再转回数字:
- 处理符号位
- 取绝对值转字符串
- 反转字符串
- 转回数字并恢复符号
- 检查是否溢出
这种方法简单易懂,但存在以下问题:
- 需要额外的字符串空间
- 多次类型转换效率较低
- 不符合”不使用 64 位整数”的题目要求(JavaScript 的 Number 是 64 位浮点数)
方法二:数学取模法(巧妙且高效)⭐
通过数学运算逐位提取并构建反转数字,这是最优解法。
核心思想:
- 用
x % 10获取当前最后一位数字 - 用
x / 10去掉最后一位 - 用
result * 10 + digit将数字添加到结果的末尾
为什么巧妙:
-
负数处理的妙用
- 在 JavaScript 中,
-123 % 10 = -3(保留符号) - 这意味着负数可以和正数用完全相同的逻辑处理,无需单独判断符号!
- 在 JavaScript 中,
-
位运算截断的技巧
(x / 10) | 0相当于Math.trunc(x / 10)|0会将浮点数转为 32 位有符号整数并截断小数部分- 比
Math.floor()更快,且对正负数都有效
-
溢出检测的精妙之处
(result | 0) === result是溢出检测的关键- 如果
result超出 32 位整数范围,|0操作会将其截断/溢出 - 截断后的值与原值不相等,说明发生了溢出
- 这种方法无需显式比较边界值,简洁高效
-
空间复杂度优化
- 完全通过数学运算实现,不需要字符串或数组等额外空间
- 只用了几个变量,空间复杂度 O(1)
代码实现
字符串反转法
function reverse(x: number): number {
const isNegative = x < 0;
const reversedStr = Math.abs(x).toString().split("").reverse().join("");
const reversedNum = isNegative ? -Number(reversedStr) : Number(reversedStr);
// 检查是否超出 32 位有符号整数范围
const INT_MAX = Math.pow(2, 31) - 1;
const INT_MIN = -Math.pow(2, 31);
if (reversedNum < INT_MIN || reversedNum > INT_MAX) {
return 0;
}
return reversedNum;
}
数学取模法(推荐 · 参考他人思路)⭐
function reverse(x: number): number {
let result = 0;
while (x !== 0) {
// 提取最后一位数字(负数会保留负号)
const digit = x % 10;
// 构建反转后的数字
result = result * 10 + digit;
// 去掉最后一位(使用位运算截断小数)
x = (x / 10) | 0;
}
// 溢出检测: 如果 result 超出 32 位整数范围,|0 会导致值改变
return (result | 0) === result ? result : 0;
}
执行流程示例
以 x = -123 为例:
| 循环 | x 初始值 | digit (x%10) | result 计算 | x 更新 ((x/10)|0) |
|---|---|---|---|---|
| 1 | -123 | -3 | 0×10 + (-3) = -3 | -12 |
| 2 | -12 | -2 | -3×10 + (-2) = -32 | -1 |
| 3 | -1 | -1 | -32×10 + (-1) = -321 | 0 |
| 结束 | 0 | - | -321 | - |
溢出检测: (-321 | 0) === -321 → true,返回 -321