回文数
1199 字
6 分钟
回文数
- 难度:简单
- 标签:数学、字符串
题目描述
Note
原题说明:
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
例如,121 是回文,而 123 不是。
示例 1
- 输入:
x = 121 - 输出:
true
示例 2
- 输入:
x = -121 - 输出:
false - 解释:从左向右读为
-121,从右向左读为121-。因此它不是一个回文数。
示例 3
- 输入:
x = 10 - 输出:
false - 解释:从右向左读为
01。因此它不是一个回文数。
提示
进阶:你能不将整数转为字符串来解决这个问题吗?
Tip
直观规律:
- 负数一定不是回文数(因为有符号位
-)。 - 除了 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; }};复杂度分析
- 时间复杂度:。对于每次迭代,我们都会将输入除以 ,因此迭代次数为数字的位数,即 。
- 空间复杂度:。我们只需要常数个变量来存储反转后的数字。
方案二:字符串双指针法
题目中提到了一个进阶要求:你能不将整数转为字符串来解决这个问题吗?
虽然数学法更优雅,但字符串辅助法在面试中也是一种非常清晰的思路。
源码实现
#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; }};复杂度分析
- 时间复杂度: 或 。其中 是数字的位数。转换字符串和双指针遍历各需 时间。
- 空间复杂度: 或 。我们需要额外的空间来存储转换后的字符串。
技巧提示:
to_string是 C++11 标准引入的函数,非常方便。- 这种方法的时间复杂度也是 O(n),但因为涉及字符串分配,空间开销略大。
测试案例分析
在编写 LeetCode 题目时,务必考虑以下必测案例:
| 类型 | 输入 | 期望输出 | 备注 |
|---|---|---|---|
| 负数 | -121 | false | 符号位不对称 |
| 尾 0 | 120 | false | 反转后前导 0 丢失 |
| 个位数 | 7 | true | 天然对称 |
| 奇数位 | 12321 | true | x == revertedNumber / 10 |
| 偶数位 | 1221 | true | x == revertedNumber |
| 最大范围 | 2147447412 | true | 需考虑 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
力扣官方题解:回文数 - 官方题解
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
最后更新于 2025-09-27,距今已过 214 天
部分内容可能已过时
相关文章 智能推荐
1
合并两个有序数组
算法 力扣第88题:合并两个有序数组。从正向合并的繁琐到逆向双指针的极简之美,实现 $O(m+n)$ 的高效原地合并。
2
删除有序数组中的重复项
算法 力扣第26题:原地删除有序数组中的重复项。从基础的标记替换,到快慢指针(Two Pointers)的高效演进。
3
罗马数字转整数
算法 力扣第13题:罗马数字转整数。探索如何处理特殊减法规则,并对比函数映射与哈希表两种实现方式。
4
最后一个单词的长度
算法 力扣第58题:最后一个单词的长度。从反向遍历的直观思想到双指针的精准定位,掌握字符串处理的边界细节。
5
找出字符串中第一个匹配项的下标
算法 力扣第28题:在字符串中寻找子串。从朴素的滑动窗口到 KMP 算法的“跳跃”艺术,深度剖析字符串匹配的性能巅峰。
随机文章 随机推荐