力扣9.回文数-转字符双指针和反转数字

问题描述

给定一个整数 x,判断它是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

示例 1:

复制代码
输入:x = 121
输出:true

示例 2:

复制代码
输入:x = -121
输出:false
解释:从左向右读为 -121,从右向左读为 121-,因此不是回文数。

示例 3:

复制代码
输入:x = 10
输出:false
解释:从右向左读为 01,因此不是回文数。

进阶要求: 你能不将整数转为字符串来解决这个问题吗?

解法一:字符串转换法(简单直观)

这是最直观的解法,将整数转换为字符串,然后用双指针比较。

java 复制代码
public boolean isPalindrome(int x) {
    // 将整数转换为字符串
    String str = String.valueOf(x);
    int left = 0, right = str.length() - 1;
    
    // 双指针向中间移动比较
    while (left < right) {
        if (str.charAt(left) != str.charAt(right)) {
            return false;
        }
        left++;
        right--;
    }
    
    return true;
}

复杂度分析:

  • 时间复杂度:O(n),其中 n 是数字的位数

  • 空间复杂度:O(n),需要额外的字符串存储空间

优缺点:

  • ✅ 代码简单,易于理解

  • ❌ 需要额外空间创建字符串

  • ❌ 不符合进阶要求

解法二:完全反转数字法

不转换为字符串,直接通过数学运算反转整个数字,然后与原数字比较。

java 复制代码
public boolean isPalindrome(int x) {
    // 负数不可能是回文数
    if (x < 0) {
        return false;
    }
    
    int reversed = 0;
    int original = x;  // 保存原始值
    
    // 反转数字
    while (x != 0) {
        // 每次取出x的个位数,加到reversed的末尾
        reversed = reversed * 10 + x % 10;
        x /= 10;  // 去掉x的个位数
    }
    
    // 比较反转后的数字与原始数字
    return reversed == original;
}

复杂度分析:

  • 时间复杂度:O(log₁₀x),循环次数等于数字的位数

  • 空间复杂度:O(1),只使用了常数级别的额外空间

注意事项:

这种方法有一个潜在问题:反转后的数字可能超出int的范围(虽然对于回文数判断来说,溢出不会影响结果正确性)。

解法三:反转一半数字法(最优解)

这是最高效的解法,只需要反转数字的一半,然后与另一半比较。

java 复制代码
public boolean isPalindrome(int x) {
    // 特殊情况:
    // 1. 负数不是回文数
    // 2. 以0结尾的数(0本身除外)不是回文数
    if (x < 0 || (x % 10 == 0 && x != 0)) {
        return false;
    }
    
    int reversedHalf = 0;
    // 当原始数字大于反转数字时,继续循环
    while (x > reversedHalf) {
        // 将x的个位数加到reversedHalf的末尾
        reversedHalf = reversedHalf * 10 + x % 10;
        x /= 10;  // 去掉x的个位数
    }
    
    // 对于偶数位数字:x == reversedHalf
    // 对于奇数位数字:x == reversedHalf / 10(去掉中间位)
    return x == reversedHalf || x == reversedHalf / 10;
}

复杂度分析:

  • 时间复杂度:O(log₁₀x/2),只需要反转一半的数字

  • 空间复杂度:O(1),只使用了常数级别的额外空间

为什么这是最优解?

  1. 避免了完全反转可能导致的溢出问题

  2. 减少了一半的循环次数

  3. 空间复杂度最低

  4. 代码简洁,逻辑清晰

性能对比

方法 时间复杂度 空间复杂度 优点 缺点
字符串转换 O(log₁₀x) O(log₁₀x) 简单直观 额外空间开销
完全反转 O(log₁₀x) O(1) 空间最优 可能溢出
反转一半 O(log₁₀x/2) O(1) 最优解 -

边界情况处理

在实现回文数判断时,需要考虑以下边界情况:

  1. 负数:所有负数都不是回文数

  2. 末尾为0:除了0本身,所有以0结尾的数字都不是回文数

  3. 整数溢出:在反转数字时要注意溢出问题

  4. 单个数字:0-9都是回文数

面试建议

在面试中遇到这个问题时,我建议:

  1. 先问清楚要求:是否需要考虑负数?是否允许转换为字符串?

  2. 从简单方法开始:先提出字符串转换法,展示基本思路

  3. 逐步优化:提出完全反转数字法,分析可能的问题(溢出)

  4. 提出最优解:展示反转一半数字法,解释为什么这是最优解

  5. 讨论边界情况:展示对边界情况的考虑

  6. 准备其他解法:如果时间允许,可以提一下数学方法

常见面试问题

  1. "为什么反转一半数字的方法更好?"

    • 答:因为它避免了完全反转可能导致的溢出问题,并且减少了一半的计算量。
  2. "如何处理负数?"

    • 答:根据回文数的定义,负数都不是回文数,因为负号在前端。
  3. "如果数字特别大,你的方法还能工作吗?"

    • 答:反转一半数字的方法不会反转整个数字,所以不会溢出。对于数学方法,我们只比较最高位和最低位,也不会溢出。

总结

判断整数是否是回文数有多种解法,每种解法都有其适用场景:

  • 日常编程:字符串转换法最简单直接

  • 面试场景:反转一半数字法最优,体现了对问题的深入理解

  • 算法竞赛:根据具体限制条件选择合适的方法

掌握多种解法不仅能帮助我们解决具体问题,更能提升我们分析问题和优化算法的能力。

相关推荐
A-Jie-Y9 小时前
JAVA设计模式-抽象工厂模式
java·设计模式
AI科技星9 小时前
ELN 升级:π 级数自动生成器全域数理架构
大数据·人工智能·python·算法·金融
强盛机器学习~9 小时前
2026年SCI一区新算法-傅里叶变换优化算法(FTO)-公式原理详解与性能测评 Matlab代码免费获取
算法·matlab·进化计算·群体智能·傅里叶变换·元启发式算法
王老师青少年编程9 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【跳跃与过河问题】:过河问题
c++·算法·贪心·csp·信奥赛·跳跃与过河问题·过河问题
@insist1239 小时前
信息安全工程师-密码学专题(下):构建可信网络空间的核心机制
java·大数据·密码学·软考·信息安全工程师·软件水平考试
摇滚侠9 小时前
Java 零基础全套视频教程,面向对象(高级),笔记 105-120
java·开发语言·笔记
叶落阁主9 小时前
Spring Boot 4 实战:Jackson 2.x 升级到 3.x 踩坑全记录
java·后端·架构
布吉岛的石头9 小时前
Java 中高级面试:JVM 内存模型 + GC 算法高频题总结
java·jvm·面试
2301_7926748610 小时前
java学习(day32)
java
沉默-_-10 小时前
备战蓝桥杯-哈希
c++·学习·算法·蓝桥杯·哈希算法