题目
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 1:
输入: 121
输出: true
示例 2:
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:
输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。
进阶:
你能不将整数转为字符串来解决这个问题吗?
解题思路
解法一:转字符数组
将数字先转成字符串,再转换成字符数组。设置 left、right 两个双指针,分别从前往后、从后往前遍历。当遇到不一样的字符时,直接返回 false;如果相同,继续遍历;当遍历完字符数组之后,也没发现不同的字符,则返回true。
复杂度分析:
时间复杂度:O(n)。我们需要遍历整个字符数组。
空间复杂度:O(n)。我们需要O(n)的空间存放字符数组。
解法二:数学解法
将数字本身反转,然后将反转后的数字与原始数字进行比较,如果它们是相同的,那么这个数字就是回文。但是,如果反转后的数字大于 INT.MAX,将遇到整数溢出问题。所以我们考虑只反转 int 数字的一半,如果该数字是回文,其后半部分反转后应该与原始数字的前半部分相同。
例如,输入 1221,我们可以将数字 “1221” 的后半部分从 “21” 反转为 “12”,并将其与前半部分 “12” 进行比较,因为二者相同,所以数字 1221 是回文。
在开始反转之前先处理一些临界情况:1)所有负数都不可能是回文;2)除了 0 以外,所有个位是 0 的数字不可能是回文,因为最高位不等于 0,所以我们可以对所有大于 0 且个位是 0 的数字返回 false。
对于其他正常情况的反转,例如数字 1221,如果执行 1221 % 10,我们将得到最后一位数字 1,要得到倒数第二位数字2,我们可以先通过除以 10 把最后一位数字 1 从 1221 中移除,1221 / 10 = 122,再将结果对 10 取余,122 % 10 = 2,就可以得到倒数第二位数字。然后我们把最后一位数字乘以 10,再加上倒数第二位数字,1 * 10 + 2 = 12,就得到了我们想要的反转后的数字。继续这个过程,将得到更多位数的反转数字。
由于整个过程我们不断将原始数字除以 10,然后给反转后的数字乘上 10,所以,当原始数字小于或等于反转后的数字时,就意味着我们已经处理了一半位数的数字了。
由于回文数的位数可奇可偶,所以当它的长度是偶数时,它对折过来应该是相等的;当它的长度是奇数时,那么它对折过来后,有一个的长度需要去掉一位数(除以 10 并取整)。
具体步骤如下:
1)先判断临界情况。
2)每次进行取余操作 ( %10),取出最低的数字:y = x % 10.
3)将最低的数字加到取出数的末尾:res = res * 10 + y.
4)每取一个最低位数字,x 都要自除以 10.
5)判断 x 是不是小于 res ,当它小于的时候,说明数字已经对半或者过半了。
6)最后,判断奇偶数情况:如果是偶数的话,res 和 x 相等;如果是奇数的话,最中间的数字就在res 的最低位上,将它除以 10 以后应该和 x 相等。
复杂度分析:
时间复杂度:O(logn)。对于每次迭代,我们会将输入除以 10,因此时间复杂度为 O(logn)。
空间复杂度:O(1)。我们只需要常数空间存放若干变量。
代码
解法一:转字符数组
class Solution {
public boolean isPalindrome(int x) {
String s = String.valueOf(x);
char[] nums = s.toCharArray();
int left = 0;
int right = nums.length-1;
while(left<=right){
if(nums[left]==nums[right]){
left++;
right--;
}else{
return false;
}
}
return true;
}
}
解法二:数学解法
class Solution {
public boolean isPalindrome(int x) {
// 临界情况
if(x<0 || (x%10==0 && x!=0)){
return false;
}
int res = 0;
// 进行反转
while(x>res){
res = res*10 + x%10;
x /= 10;
}
// 处理奇偶情况
return x == res || x == (res / 10);
}
}