回文数

1199 字
6 分钟
回文数

题目链接:9. 回文数 - 力扣(LeetCode)

  • 难度:简单
  • 标签:数学、字符串

题目描述#

Note

原题说明: 给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

例如,121 是回文,而 123 不是。

示例 1#

  • 输入x = 121
  • 输出true

示例 2#

  • 输入x = -121
  • 输出false
  • 解释:从左向右读为 -121,从右向左读为 121-。因此它不是一个回文数。

示例 3#

  • 输入x = 10
  • 输出false
  • 解释:从右向左读为 01。因此它不是一个回文数。

提示#

  • 231x2311-2^{31} \le x \le 2^{31} - 1

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


Tip

直观规律

  1. 负数一定不是回文数(因为有符号位 -)。
  2. 除了 0 以外,以 0 结尾的数字一定不是回文数(因为最高位不可能是 0)。

方案一:数学法(反转一半数字)#

最初我想通过对全数进行取余反转,但那样容易触发 整型溢出

进阶思路: 我们并不需要反转整个数字。只需要将数字的后一半进行反转,然后与前一半进行比较。如果相等(或对于奇数位数字,反转后的数字除以 10 后相等),则该数是回文数。

我的第一版代码(纠错版)#

最初的代码写得很烂,存在以下典型错误:

class Solution {
public:
bool isPalindrome(int x) {
if(x < 0){
return false;
}
else{
continue; // 错误 1:continue 只能用于循环
}
for(int i = 0, i <= sizeof(x)/2; i++) // 错误 2:逗号分隔符错误,且逻辑不对
{
int y = 0;
y = y * 10 + x % 10;
x /= 10;
}
return x == y || x == y / 10;
}
};

完善后的数学解法#

经过多次调整(主要解决了 0 的特殊处理和 10 的倍数逻辑),最终成型如下:

class Solution {
public:
bool isPalindrome(int x) {
// 特殊情况:
// 1. 负数不是回文数
// 2. 最后一位是 0 且该数不是 0,则不是回文数
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}
int revertedNumber = 0;
while (x > revertedNumber) {
revertedNumber = revertedNumber * 10 + x % 10;
x /= 10;
}
// 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
// 例如,12321,在 while 循环结束时 x = 12,revertedNumber = 123,
// 由于处于中位的数字不影响回文(它总是等于自己),我们可以简单地将其去除。
return x == revertedNumber || x == revertedNumber / 10;
}
};

复杂度分析#

  • 时间复杂度O(log10n)O(\log_{10}n)。对于每次迭代,我们都会将输入除以 1010,因此迭代次数为数字的位数,即 log10n\log_{10}n
  • 空间复杂度O(1)O(1)。我们只需要常数个变量来存储反转后的数字。

方案二:字符串双指针法#

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

虽然数学法更优雅,但字符串辅助法在面试中也是一种非常清晰的思路。

源码实现#

#include <string>
#include <algorithm>
using namespace std;
class Solution {
public:
bool isPalindrome(int x) {
if (x < 0) return false;
string s = to_string(x); // 整数转字符串
int left = 0, right = s.size() - 1;
while (left < right) {
if (s[left] != s[right]) {
return false;
}
left++;
right--;
}
return true;
}
};

复杂度分析#

  • 时间复杂度O(L)O(L)O(log10n)O(\log_{10}n)。其中 LL 是数字的位数。转换字符串和双指针遍历各需 O(L)O(L) 时间。
  • 空间复杂度O(L)O(L)O(log10n)O(\log_{10}n)。我们需要额外的空间来存储转换后的字符串。

技巧提示

  1. to_string 是 C++11 标准引入的函数,非常方便。
  2. 这种方法的时间复杂度也是 O(n),但因为涉及字符串分配,空间开销略大。

测试案例分析#

在编写 LeetCode 题目时,务必考虑以下必测案例

类型输入期望输出备注
负数-121false符号位不对称
尾 0120false反转后前导 0 丢失
个位数7true天然对称
奇数位12321truex == revertedNumber / 10
偶数位1221truex == revertedNumber
最大范围2147447412true需考虑 int 溢出(反转一半可避免)

总结与扩展#

翻看评论区时发现了一个极其简洁的“一行代码”思路(使用了 STL 容器特性):

class Solution {
public:
bool isPalindrome(int x) {
string t = to_string(x);
string r = t;
reverse(r.begin(), r.end());
return t == r;
}
};

虽然这种做法在实际比赛中能极速出题,但在学习算法阶段,理解反转一半数字的数学思想对培养逻辑更有帮助!


Note

力扣官方题解:回文数 - 官方题解

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

回文数
https://firefly-7a0.pages.dev/posts/leetcode_notes/9palindrome-number/
作者
lonelystar
发布于
2025-09-27
许可协议
CC BY-NC-SA 4.0
最后更新于 2025-09-27,距今已过 214 天

部分内容可能已过时

评论区

Profile Image of the Author
LonelyStar
Hello, I'm LonelyStar.
公告
欢迎来到我的博客!
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
119
分类
11
标签
346
总字数
226,548
运行时长
0
最后活动
0 天前

目录