題目
判斷一個整數是否是迴文數。迴文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。
示例 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);
}
}