題目描述:
給定一個整數 x
,如果 x
是一個回文數,則返回 true
;否則返回 false
。
回文數是指無論是正序(從左到右)還是倒序(從右到左)讀取時,結果都是相同的整數。例如,121
是回文數,而 123
則不是。
Example 1:
x = 121
true
Example 2:
x = -121
false
Example 3:
x = 10
false
解題思路:
這道題目主要考驗的是解題者是否能夠將一個數字逐位拆解,並且正確地處理進位操作。通過逐位比較數字的左右兩側,我們可以判斷該數字是否為回文數。這不僅需要考慮數字的基本操作,還需要解題者靈活運用數學技巧來實現這一過程。
在十進制中,逐位拆解數字需要使用取餘數的操作,即 x % 10
。而進位操作則是將數字除以十後取整數部分,即 Math.floor(x / 10)
。當我們逐位拆解數字時,拆解完的位數需要存儲在另一個變數中(例如 revertedNumber
)。需要注意的是,每次儲存前,都必須將前一次的結果進位(乘以 10)後再將當前位數相加。這樣才能確保數字逐位拆解並且正確重組。當 revertedNumber
大於原本的 x
時,就可以停止while迴圈的操作並比較結果。此時,例如 x = 1
和 revertedNumber = 12
,由於中位數不影響回文(因為它總是與自己相等),我們可以簡單地將 revertedNumber
除以 10 去除中位數,再與 x
進行比較。如果兩者相等,則該數字是回文數。
此外,從 Example 2 和 Example 3 可以看出,負數以及尾數為 0 的數字都不會是回文數。唯一的例外是數字 0,因為它只有一個位數,所以是回文數。基於這些觀察,我們可以在開始時先排除不可能是回文數的情況,這樣就可以更高效地進行後續的 while 迴圈判斷和處理。
var isPalindrome = function(x) {
if(x < 0) return false;
if(x == 0) return true;
if(x % 10 == 0) return false;
let revertedNumber = 0;
while (x > revertedNumber) {
revertedNumber = revertedNumber * 10 + x % 10;
x = Math.floor(x / 10);
}
return x === revertedNumber || x === Math.floor(revertedNumber / 10);
};
時間複雜度: O(log n),因為在每次 while 迴圈中,我們將輸入數字 x 除以 10。最壞情況下,迴圈會執行 n 個位數的一半次數,即大約是 log(n) 次。
空間複雜度: O(1),因為我們只使用了常數空間來存儲幾個變數,不需要額外的陣列或其他數據結構。這意味著無論 x 的大小如何,所需的額外空間都是固定的。
除了上述的解法之外,對於熟悉 JavaScript 的讀者來說,應該能想到一種更簡便且直觀的解法。這裡我們稍微討論一下這個解法,但由於它依賴於 JavaScript 本身提供的 API,不一定適用於其他語言,因此僅供參考。
在 JavaScript 中,我們可以通過以下步驟快速檢查一個數字是否為回文數:
首先,將數字轉換為字串(string),使用 x.toString() 方法。
然後,將該字串轉換為陣列(Array),以便能夠使用陣列的操作方法。這一步使用 str.split(''),將字串分割成單個字符的陣列。
接著,對該陣列進行反轉操作,使用 reverse() 方法來反轉陣列中的元素順序。
最後,將反轉後的陣列重新轉回字串,使用 join('') 方法將陣列中的元素連接成一個字串,然後將其與原始字串進行比較。
這種方法非常簡單,且對於熟悉 JavaScript API 的開發者來說非常直觀。然而,這種解法的效率會略低於上面的數學方法,因為它涉及多次字串和陣列的轉換操作,不過在大多數情況下仍然能夠快速解決問題。
var isPalindrome = function(x) {
if (x < 0) {
return false;
}
const str = x.toString();
const reversedStr = str.split('').reverse().join('');
return str === reversedStr;
};
時間複雜度: O(n),其中 n 是整數 x 轉換為字串後的長度。字串的反轉和比較操作的時間複雜度都是 O(n),因為這些操作需要遍歷整個字串。
空間複雜度: O(n),因為我們需要額外的空間來存儲字串的反轉結果。在進行反轉操作時,會創建一個新陣列來保存反轉後的字串,這就佔用了額外的記憶體空間。因此,整個過程的空間複雜度與字串的長度成正比。
總結:
透過這道題目,LeetCode 教會我們如何對數字進行拆解和重組,而這個技巧在後續的題目中會反復出現,可見其重要性。此外,現代程式語言通常提供豐富的 API,這些 API 不僅在解 LeetCode 時有用,在日常工作中也能加速我們的工作流程。只要在不顯著犧牲時間和空間複雜度的情況下,利用 API 來解題也是一種有效的解題思路。
對於這道題,我們可以將其歸類為「while 迴圈」和「array.reverse」這兩個分類。這樣的分類方式有助於我們在日後回顧時,更清晰地理解不同解法所涉及的核心概念和技巧。