力扣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. "如果数字特别大,你的方法还能工作吗?"

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

总结

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

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

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

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

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

相关推荐
qq_410194294 分钟前
.NET 8.0 下基于 PaddleOCRSharp 的离线文字识别落地指南
算法·.net
此时不提桶,更待何时4 分钟前
02-02-B-AQS与JUC锁面试与生产事故实战
java
音符犹如代码7 分钟前
Kafka 接入 AI 的三条路线:MCP 提案、会话记忆与实时上下文
java·大数据·ai·kafka
Omics Pro7 分钟前
1个月2轮融资!长寿虚拟细胞
数据库·人工智能·算法·机器学习·自然语言处理
residual_fan8 分钟前
航空发动机故障诊断专用智能体(六):实际机队健康管理中的应用考量与展望
人工智能·算法·数据挖掘·数据分析
vx_BS8133011 分钟前
【项目编号:project51629】Spring Boot 乡村自来水缴费系统:把抄表、水费生成与在线缴费做成一条数字化闭环
java·spring boot·eclipse·tomcat·maven
qq_2695067520 分钟前
第29课-Servlet基础
java
hansang_IR30 分钟前
【讲解】CSP-S2026 第一轮初赛
c++·算法
毅炼31 分钟前
不写多语言 SDK,怎么让 Python、Go、Node 服务接入注册中心?
java·后端·系统架构·gateway
hanlin0332 分钟前
刷题笔记:力扣第76题-最小覆盖子串
笔记·算法·leetcode