1. 整数翻转问题背景与核心挑战
今天想和大家分享一道经典的LeetCode算法题——整数翻转(第7题)。这道题看似简单,却隐藏着不少值得深思的细节。作为华为OD等大厂笔试的常客,它考察的不仅是基础编码能力,更是对边界条件的处理意识。
题目要求很简单:给定一个32位有符号整数x,返回其数字部分反转后的结果。如果反转后整数超过32位有符号整数范围[-2³¹, 2³¹-1],就返回0。假设环境不允许存储64位整数。
举个例子:
- 输入123 → 输出321
- 输入-123 → 输出-321
- 输入120 → 输出21
关键点:这道题真正的难点不在于反转逻辑本身,而在于如何处理溢出情况。这也是面试官最关注的考察点。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础解法与溢出陷阱
2.1 字符串反转法的局限性
很多人的第一反应是用字符串操作:
python复制def reverse(x):
s = str(abs(x))[::-1]
if x < 0:
s = '-' + s
return int(s) if -2**31 <= int(s) <= 2**31-1 else 0
这种方法虽然直观,但存在几个问题:
- 效率较低:字符串操作和类型转换开销大
- 没有真正解决溢出问题:在最后一步int(s)时可能已经溢出
- 不符合题目"不允许存储64位整数"的要求(某些语言实现可能违反)
2.2 数学方法的正确实现
更优雅的解法是用数学运算逐步构建反转数:
python复制def reverse(x):
res = 0
sign = -1 if x < 0 else 1
x = abs(x)
while x != 0:
pop = x % 10
x = x // 10
# 检查正溢出
if sign == 1 and (res > 214748364 or (res == 214748364 and pop > 7)):
return 0
# 检查负溢出
if sign == -1 and (res > 214748364 or (res == 214748364 and pop > 8)):
return 0
res = res * 10 + pop
return res * sign
这里有几个关键细节:
- 我们统一处理绝对值,最后再恢复符号
- 每次迭代都检查是否会溢出(比最后统一检查更安全)
- 214748364是2³¹//10的整数部分,7和8分别是INT_MAX和INT_MIN的最后一位
3. 溢出检测的工程化思考
3.1 为什么要在每一步检查溢出
很多初学者会问:为什么不在最后统一检查是否超出[-2³¹, 2³¹-1]范围?这是因为:
- 在反转过程中,中间结果可能已经溢出32位整数范围
- 某些语言(如C++)的溢出行为是未定义的
- 题目明确限制不能使用64位存储
3.2 边界条件的完整测试用例
为了确保代码健壮性,应该测试这些边界情况:
python复制测试用例:
正常情况:123 → 321
负数:-123 → -321
末尾有0:120 → 21
最小负数:-2147483648 → 0(反转后会正溢出)
最大正数:2147483647 → 0(部分反转步骤就会溢出)
单个数字:5 → 5
10的幂次:100 → 1
4. 算法优化与语言特性
4.1 位运算优化(C++示例)
在某些语言中可以用位运算加速:
cpp复制int reverse(int x) {
int rev = 0;
while (x != 0) {
int pop = x % 10;
x /= 10;
if (rev > INT_MAX/10 || (rev == INT_MAX/10 && pop > 7)) return 0;
if (rev < INT_MIN/10 || (rev == INT_MIN/10 && pop < -8)) return 0;
rev = rev * 10 + pop;
}
return rev;
}
这里直接使用INT_MAX/INT_MIN常量,避免了硬编码魔数。
4.2 Python的无限精度特性
Python的整数理论上可以无限大,但这道题要求模拟32位环境。我遇到过的一个真实坑是:
python复制# 错误示例:依赖Python自动处理大整数
def reverse(x):
res = int(str(abs(x))[::-1]) * (-1 if x <0 else 1)
return res if -2**31 <= res <= 2**31-1 else 0
虽然测试能过,但面试时会被指出不符合"不允许存储64位整数"的限制。
5. 华为OD笔试的实战建议
根据近期华为OD笔试的反馈,这类题目常出现在第一轮机考中。我的备考建议是:
- 手写实现至少3种解法(字符串/数学/位运算)
- 准备完整的测试用例集(特别是边界情况)
- 时间复杂度分析:O(log₁₀x)(因为循环次数与数字位数成正比)
- 空间复杂度:O(1)(只用了常数空间)
一个容易忽略的点是:在华为OD的C++环境中,INT_MIN的绝对值会比INT_MAX大1(因为补码表示),这在处理-2147483648时要特别注意。
6. 同类问题拓展
掌握这个模式后,可以解决一系列类似问题:
- 回文数判断(LeetCode 9)
- 反转二进制位(LeetCode 190)
- 字符串转整数(LeetCode 8)
以回文数为例,可以复用整数反转的逻辑:
python复制def isPalindrome(x):
if x < 0: return False
return x == reverse(x)
最后分享一个我在面试中遇到的变种题:如何反转一个浮点数的小数部分?比如输入123.456→123.654。这需要处理小数点定位和末尾零的问题,留给大家思考。
