0009 - Palindrome Number(回文數)
大意說明
簡單來說就是找到類似於 121 的回文數(就是往前讀往後讀都是 121,英文會長得類似是 abcba 這種東東)
自己的思考過程(逆向字串解)
有幾種想法,一開始先想到透過轉成字串陣列,然後用迴圈做起頭和尾巴的不斷比較,迴圈範圍為字串陣列長度 / 2。
但很顯然地這個會先碰到不同語言對於除法小數的問題,導致無法過關。
例如以下 Python Code 就會卡到 / 2 的問題:
class Solution:
def isPalindrome(self, x: int) -> bool:
if x < 0:
return False
number_str = str(x)
result = False
for i in range(0, int(len(number_str) / 2)): # 如果遇到 0 <= x <= 9,len / 2 會是 0
if number_str[i] == number_str[len(number_str) - 1 - i]:
result = True
else:
result = False
return result
所以後來改開新的 list,倒轉加入之後再把 list 合併成一個字串,就過了:
class Solution:
def isPalindrome(self, x: int) -> bool:
if x < 0:
return False
number_str = str(x)
reverse_num = []
for i in range(0, len(number_str), 1):
reverse_num.append(number_str[len(number_str) - 1 - i])
return "".join(reverse_num) == number_str
但如果要逆向字串的話,Python 對於字串有內建方法 - Slice:
class Solution:
def isPalindrome(self, x: int) -> bool:
num_str = str(x)
reversed_num = num_str[::-1] # Reverse slice
return reversed_num == num_str
Java 版本一開始想到的比較麻煩,轉成 String 之後,又要轉成 Char Array 之後才能做逆向加入,且還要開 StringBuilder (不開也可以但就很耗能):
class Solution {
public boolean isPalindrome(int x) {
String numStr = String.valueOf(x);
char[] numChrArray = numStr.toCharArray();
StringBuilder builder = new StringBuilder();
for(int i = 0;i < numChrArray.length; i++){
builder.append(numChrArray[numChrArray.length - 1 - i]);
}
return numStr.equals(builder.toString());
}
}
後來查到可以用 String.charAt()
,於是可以少開一個 Char Array:
class Solution {
public boolean isPalindrome(int x) {
String numStr = String.valueOf(x);
StringBuilder reverseNum = new StringBuilder();
for(int i = 0;i < numStr.length(); i++){
reverseNum.append(numStr.charAt(numStr.length() - 1 - i));
}
return numStr.equals(reverseNum.toString());
}
}
有效率的解法 : 數學解
不要做字串轉換,直接做數學計算
除法模數解
- 先判斷是不是小於 0 (因為負數不可能是回文數)
- 跑迴圈
- 用模數取得個位數 (% 10)
- 把個位數加入到另外一個變數當中
- 跑下一次迴圈
- 前面步驟一樣,用模數取得個位數,但是在加入到另外一個變數之前,另外一個變數要先進位 (x 10)
- 跑下一次迴圈
- 迴圈結束條件:當所有的位數都取完了就結束
- 另外一個變數跟原本的數字去比較
相關程式碼如下,以下範例為 Java:
class Solution {
public boolean isPalindrome(int x) {
if(x < 0){
return false;
}
long temp = x;
long reversed = 0;
while(temp != 0){
long y = temp % 10;
reversed = reversed * 10 + y;
temp /= 10;
}
return x == reversed;
}
}
一半數字解
道理跟前面解法差不多,但是只有算一半,可以減少時間複雜度和空間複雜度,只是
- 要多做先前判斷:像 10 這種可以被 10 整除但模數等於 0 的數字絕對不可能是回文數
- 因為位數有奇偶,如果遇到奇數位數,最後判斷的時候要捨去一個位數,因為最後一次加入的數字是中間數(反正中間數肯定是一樣的)
- 迴圈結束條件會變成當逆向數大於等於原先數字被不斷除以 10 的結果
以下為範例程式碼:
class Solution {
public boolean isPalindrome(int x) {
if((x < 0) || (x != 0 && x % 10 == 0)){ // 多做一個 x 不是 0 但是模數 10 卻是 0 的狀況(這不可能是回文數)
return false;
}
long reversed = 0;
while(x > reversed){ // 如果 x 被 10 除到最後小於等於 reversed,結束 loop
long y = x % 10;
reversed = reversed * 10 + y;
x /= 10;
}
return (x == reversed) || (x == reversed / 10); // reversed / 10 捨去一位的原因是,最後一位往往都是奇數位數的中間
}
}