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

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

总结

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

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

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

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

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

相关推荐
skywalker_112 小时前
网络编程篇
java·网络协议·网络编程
热爱编程的小刘2 小时前
Lesson04---类与对象(下篇)
开发语言·c++·算法
毕设源码-朱学姐2 小时前
【开题答辩全过程】以 基于Java的九价疫苗预约系统为例,包含答辩的问题和答案
java·开发语言
tb_first2 小时前
SSM速通4
java·jvm·spring·tomcat·maven·mybatis
梦梦代码精2 小时前
开源、免费、可商用:BuildingAI一站式体验报告
开发语言·前端·数据结构·人工智能·后端·开源·知识图谱
百炼成神 LV@菜哥2 小时前
Kylin Linux V10 aarch64安装DBeaver
java·linux·服务器·kylin
有代理ip2 小时前
成功请求的密码:HTTP 2 开头响应码深度解析
java·大数据·python·算法·php
YYuCChi3 小时前
代码随想录算法训练营第三十四天 | 62.不同路径、63.不同路径||
算法
小明同学013 小时前
[C++进阶] 深度解析AVLTree
c++·算法·visualstudio