力扣7.整数反转-从基础到边界条件

问题描述

给定一个32位有符号整数 x,返回将其数字部分反转后的结果。如果反转后整数超出32位有符号整数范围 [-2³¹, 2³¹-1],则返回0。

示例:

  • 输入:123 → 输出:321

  • 输入:-123 → 输出:-321

  • 输入:120 → 输出:21

  • 输入:1534236469 → 输出:0(反转后9646324351 > 2147483647)

基础算法:反转数字

1. 核心思路

通过循环取模 运算获取数字的最后一位 ,然后推到结果rev的末尾

java 复制代码
while (x != 0) {
    int digit = x % 10;      // 获取最后一位
    rev = rev * 10 + digit;  // 最后一位推入结果数的末尾
    x /= 10;                 // 移除x最后一位
}

2. 处理负数

Java的取模运算对负数也有效:-123 % 10 = -3,因此上述代码可以直接处理负数。

核心挑战:整数溢出

1. 为什么需要处理溢出?

32位有符号整数的范围是 -21474836482147483647。反转后的数字可能超出这个范围,例如:

  • 1534236469 反转后为 9646324351 > 2147483647

2. 溢出检查的原理

我们需要在执行 rev = rev * 10+ digit 之前进行检查,因为一旦计算完成,溢出已经发生。

检查条件推导:

对于正数溢出:

  • 如果 rev > Integer.MAX_VALUE / 10,那么 rev * 10 肯定溢出

  • 如果 rev == Integer.MAX_VALUE / 10,那么需要 digit ≤ 7(因为 Integer.MAX_VALUE = 2147483647

对于负数溢出:

  • 如果 rev < Integer.MIN_VALUE / 10,那么 rev * 10 肯定溢出

  • 如果 rev == Integer.MIN_VALUE / 10,那么需要 digit ≥ -8(因为 Integer.MIN_VALUE = -2147483648

完整解决方案

方案一:详细边界检查(推荐)

java 复制代码
class Solution {
    public int reverse(int x) {
        int rev = 0;
        
        while (x != 0) {
            int digit = x % 10;
            
            // 检查正数溢出
            if (rev > Integer.MAX_VALUE / 10) {
                return 0;
            }
            if (rev == Integer.MAX_VALUE / 10 && digit > 7) {
                return 0;
            }
            
            // 检查负数溢出
            if (rev < Integer.MIN_VALUE / 10) {
                return 0;
            }
            if (rev == Integer.MIN_VALUE / 10 && digit < -8) {
                return 0;
            }
            
            rev = rev * 10 + digit;
            x /= 10;
        }
        
        return rev;
    }
}

方案二:官方简化版

java 复制代码
class Solution {
    public int reverse(int x) {
        int rev = 0;
        while (x != 0) {
            if (rev < Integer.MIN_VALUE / 10 || rev > Integer.MAX_VALUE / 10) {
                return 0;
            }
            int digit = x % 10;
            x /= 10;
            rev = rev * 10 + digit;
        }
        return rev;
    }
}

官方版的巧妙之处:

看似省略了等于边界的检查,但实际上当 rev 等于边界值时,如果 digit 会导致溢出,计算后的 rev 会在下一次循环中被检查出来。虽然更简洁,但逻辑不够直观。

方案三:使用long类型(面试友好)

java 复制代码
class Solution {
    public int reverse(int x) {
        long rev = 0;
        
        while (x != 0) {
            rev = rev * 10 + (x % 10);
            x /= 10;
            
            // 检查是否超出int范围
            if (rev > Integer.MAX_VALUE || rev < Integer.MIN_VALUE) {
                return 0;
            }
        }
        
        return (int) rev;
    }
}

常见错误分析

错误1:计算后检查溢出

java

复制代码
// 错误!溢出已经发生
rev = rev * 10 + digit;
if (rev > Integer.MAX_VALUE) {  // 此时rev已经是错误的值
    return 0;
}

错误2:错误的检查条件

java

复制代码
// 错误!任何int除以10都不会超过MAX_VALUE
if (rev / 10 > Integer.MAX_VALUE) {
    return 0;
}

错误3:忽略等于边界的情况

java

复制代码
// 不完整!缺少对rev == 边界值/10 的检查
if (rev > Integer.MAX_VALUE / 10) {
    return 0;
}

数学原理深度解析

1. 边界值分析

text

复制代码
Integer.MAX_VALUE = 2147483647
Integer.MAX_VALUE / 10 = 214748364

当 rev = 214748364 时:
    rev * 10 = 2147483640
    最大可加的 digit = 2147483647 - 2147483640 = 7

2. 为什么检查要在计算前?

因为整数溢出在Java中不会抛出异常,而是会"回绕":

  • 2147483647 + 1 = -2147483648

  • 但我们希望提前检测到这种情况并返回0

面试技巧与话术

1. 逐步解决问题

  1. "首先,我会实现基本的数字反转逻辑"

  2. "然后,我需要考虑负数的处理"

  3. "最后,最重要的是处理整数溢出问题"

2. 解释检查逻辑

可以说:

"为了避免溢出,我在计算 rev * 10 + digit 之前进行检查:

  • 如果 rev 已经大于 MAX_VALUE/10,那么乘以10后肯定溢出

  • 如果 rev 等于 MAX_VALUE/10,那么需要确保 digit 不超过7"

3. 处理不确定的情况

如果不记得精确值:

"我不记得边界值的最后一位是7还是8了,但我知道原理:当 rev 等于边界值的1/10时,需要检查 digit 是否超过边界值的个位数。"

性能分析

  • 时间复杂度:O(log₁₀|x|),循环次数与数字的位数成正比

  • 空间复杂度:O(1),只使用常数空间

扩展思考

1. 如果输入是64位整数?

原理相同,但边界值变为 Long.MAX_VALUELong.MIN_VALUE

2. 如何反转浮点数?

需要处理小数点和精度问题,思路完全不同

3. 其他语言中的实现

不同语言对整数溢出的处理方式不同:

  • C/C++:未定义行为

  • Python:整数自动扩展,不会溢出

  • Java:溢出会回绕

总结

整数反转问题是一个很好的算法练习,它考察了:

  1. 基础编程能力:循环、取模、除法运算

  2. 边界条件处理:负数、零、最大值、最小值

  3. 溢出预防:在计算前进行检查

  4. 代码健壮性:考虑所有可能的输入情况

关键要点:

  • 必须在计算前进行溢出检查

  • 正数和负数的溢出检查逻辑不同

  • 边界情况(rev == 边界值/10)需要特殊处理

  • 使用long类型可以简化实现,但可能不符合某些题目要求

无论是面试还是日常编程,正确处理边界条件都是优秀程序员的重要标志。整数反转问题虽然简单,但其中的细节值得深入思考和掌握。

相关推荐
java修仙传2 小时前
力扣hot100:前K个高频元素
算法·leetcode·职场和发展
嗷嗷哦润橘_2 小时前
从萝卜纸巾猫到桌游:“蒸蚌大开门”的设计平衡之旅
人工智能·算法·游戏·概率论·桌游
小北方城市网2 小时前
微服务注册中心与配置中心实战(Nacos 版):实现服务治理与配置统一
人工智能·后端·安全·职场和发展·wpf·restful
TracyCoder1232 小时前
Java String:从内存模型到不可变设计
java·算法·string
码农丁丁2 小时前
第二十七篇 技术管理者自身的能力升级
人工智能·职场和发展·技术管理·ai时代的技术管理
我是大咖2 小时前
二维数组与数组指针
java·数据结构·算法
筵陌3 小时前
算法:动态规划
算法·动态规划
大江东去浪淘尽千古风流人物3 小时前
【DSP】xiBoxFilter_3x3_U8 dsp VS cmodel
linux·运维·人工智能·算法·vr
zhuqiyua3 小时前
【无标题】
算法