一、 题目描述
给你一个整数 x
,如果 x
是一个回文整数,输出 true
;否则,输出 false
。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
- 例如,
121
是回文,而123
不是。 -
提示:
-2
³¹<= x <= 2
³¹- 1
二、 思路分析
我们首先想到的是把数字转换为字符串,再将字符串逆序,最后比较二者是否相等。
那么此时就需要开辟一个新的空间用于存放逆序后的字符串。若我们只在这个整数上思考呢?这时,我们想到用%和/同时进行将这个整数反转,但是此时可能会造成整数溢出的问题。
为了能够避免溢出,为什么不考虑只反转该数的一半?毕竟,如果该数字是回文,其后半部分反转后应该与原始数字的前半部分相同。例如,输入 1221,我们可以将数字 “1221” 的后半部分从 “21” 反转为 “12”,并将其与前半部分 “12” 进行比较,因为二者相同,我们得知数字 1221 是回文。
三、 代码与解析
1. Python
s = str(input())
s1 = s[::-1]
if s == s1:
print("true")
else:
print("false")
如上所示,利用字符串简单的切片操作[::-1]即可得到数字的反转,同时,便捷的Python可以直接利用“==”判断两字符串是否相等。
但这样做的缺点是复杂度的牺牲,由此,我们走思路分析中的第二条路。
2. C++
#include <iostream>
int main() {
int x, half = 0;
std::cin >> x;
if(x < 0 || (x % 10 == 0 && x != 0))//若x为负数,一定不是回文数;若x不为0却以0结尾,也一定不是回文数
std::cout << "false";
else
{
while(x > half)//注意若x == half时就不该再跳入%/循环中了
{
half = half *10 + x % 10;
x /= 10;
}
if(x == half || x == half / 10)
std::cout << "true";
else
std::cout << "false";
}
return 0;
}
(1) 临界情况分析
首先,若x为负数,则其反转末尾为负号“-”,一定不与原文相等。其次,若x不为0且末尾为0,则其反转后首位为0,即少了一位,也一定不会与原文相等。
(2)如何获得后半部分的反转half
处理完临界情况,就要考虑一般情况了。对于数字 1221,如果执行 1221 % 10,我们将得到最后一位数字 1,要得到倒数第二位数字,我们可以先通过除以 10 把最后一位数字从 1221 中移除,1221 / 10 = 122,再求出上一步结果除以 10 的余数,122 % 10 = 2,就可以得到倒数第二位数字。如果我们把最后一位数字乘以 10,再加上倒数第二位数字,1 * 10 + 2 = 12,就得到了我们想要的反转后的数字。如果继续这个过程,我们将得到更多位数的反转数字。
(3) 控制循环次数
那么现在的问题是,我们如何知道反转数字的位数已经达到原始数字位数的一半?我们可以就此分为奇数位数和偶数位数两种情况。
①奇数
设一个n位数字x,一定当half为位时,才会大过剩余的x的
位数字。
②偶数
设一个n位回文数,当half和剩余的x平分n位时,half == x;非回文数的话,当half和剩余的x平分n位时,half和x的大小是不确定的,但在最后的判定时,half一定不会等于x,则可只考虑回文数情况。
因此,代码中出现了while(x > half)的循环条件,一旦当 half ≥ x 时,就跳出循环。
(4)判断是否为回文
因(3)中奇偶位数的差别,此时也有差别。
①奇数
half比x多一位,若将其“尾巴”去掉后与x相等,则是回文数,因为删掉的“尾巴”是回文数中间那个数字,对回文与否无影响。
②偶数
此时若half == x,则是回文数。
四、 重难点总结
- Python字符串切片[::-1]可实现反转;
- 回文数考虑前半与后半反转是否相等即可;
- 当思绪混乱时,可以借助具体数字,用纸笔模拟循环。