在 Java 中,迴文數是指任何正著讀和反著讀都相同的整數 — 121、1331 和 12321 是教科書上的範例,你可以透過用算術反轉 int,或是轉換成 String 後呼叫 StringBuilder.reverse() 來偵測它們。對於大多數的正式環境程式碼,String 做法是最簡短的,但整數算術版本則避免了任何字串配置,並且自然地處理像前導零這類的數值邊界情況。對於純數字輸入,兩種方法都會給出正確答案,但對於以詞組、帶腔調字母或標點符號來定義迴文的競賽或謎題,兩者都可能悄悄地產生不一致的結果。一個透明、瀏覽器內的檢查工具正好能補上這個落差:它會顯示它所使用的精確標準化比較字串,因此你可以確認你的 Java 邏輯在相同規則下產生相同的判斷。如果你的 Java 方法對 12321 回傳 true,但檢查工具回傳 no,差異幾乎總是在於每個實作在比較前移除了什麼 — 標點、大小寫或 Unicode 字母 — 而檢查工具的預覽能讓這項差異一目了然。

在 Java 中檢查迴文數的方法
兩個值得牢記的 Java 模式是整數算術和字串反轉。算術版本會對任何負數立即回傳 false,然後使用餘數和除法反轉剩餘的數位。String 版本較短,但每次呼叫會配置兩個字串。
整數算術反轉:
public static boolean isPalindromeNumber(int x) { if (x < 0) return false; int original = x; int reversed = 0; while (x > 0) { reversed = reversed * 10 + x % 10; x /= 10; } return original == reversed; }
逐步檢視 12321:迴圈依序取出 1、然後 2、然後 3、然後 2、然後 1,並建立出 reversed = 12321,等於原值,因此檢查回傳 true。對於 123,reversed 變成 321,數值不同,方法回傳 false。
任何字元序列的字串反轉:
public static boolean isPalindrome(String s) { String clean = s.replaceAll("[^A-Za-z0-9]", "").toLowerCase(); return clean.equals(new StringBuilder(clean).reverse().toString()); }
該正則表達式會去除所有非英數字元並摺疊大小寫,因此 "Race car" 會變成 "racecar" 並與其反轉相符。如果你想更深入地學習去除標點的正則表達式,在 Java 中從字串移除標點符號指南中介紹了更安全的替代方案,能保留 Unicode 字母而非默默將它們捨棄。
使用迴文檢查工具驗證邏輯
一旦你的 Java 方法編譯完成,確認它符合某個已記載規則的最快方式,就是把同一個輸入跑過迴文檢查工具,並閱讀它所顯示的標準化比較字串。這個工具完全在瀏覽器中執行,因此測試輸入永遠不會離開頁面。
- 在輸入欄位中輸入你想要測試的單字、片語、句子或數字。
- 執行檢查工具,並檢視預覽面板中顯示的標準化字母與數字字串。
- 讀取判斷結果以及旁邊顯示的保留字元數量。
- 比對所聲明的標準化規則(不區分大小寫、保留 Unicode 字母和數字、套用 NFKC、忽略標點和表情符號)與你的 Java 程式碼預計滿足的任何特定競賽規則。
- 如果判斷結果與你的 Java 輸出不一致,請查看預覽字串,以精確找出在比較前被過濾或轉換的是哪一個字元。
對於像 12321 這樣的純數字,預覽應原樣顯示這些數字,而判斷結果應為 yes。對於 "A man, a plan, a canal: Panama",預覽會摺疊為 amanaplanacanalpanama 並回傳 yes,符合 Merriam-Webster 所記載的經典片語範例。對於 "Hello",預覽為 hello,判斷結果為 no。
值得測試的 Java 迴文邊界情況
大多數 Java 迴文錯誤都出現在原作者從未想過的輸入上。將這些輸入分別跑過你的程式碼和檢查工具,就能快速暴露出規則上的差異。
- 負數。依慣例,-121 不是迴文,因為前導的負號破壞了對稱性。上方的整數方法透過提前 return 處理了這種情況;String 方法則在去除非英數的負號後,將 "-121" 視為 "121",並錯誤地回報 true。
- 前導零。"010" 作為字串時保持對稱,但解析為整數後會變成 10。如果你用 Integer.parseInt 解析 "010",就會失去前導零;如果你將該值保留為字串,對稱性測試就會通過。
- Unicode 字母。在檢查工具公布的規則下,"Été" 會標準化為 été,並且是迴文。一個只允許 [A-Za-z0-9] 的 Java 正則表達式會去除帶腔調字母,只留下 t,因此 Java 程式碼最終是在拿一個保留下來的字母與自身比較,而不是與原始單字比較。
- 混合文字與表情符號。表情符號落在檢查工具的字母與數字範圍之外,在比較時會被排除,因此 "abc😀cba" 會標準化為 "abccba" 並回傳 yes。如果你的 Java 程式碼宣稱要套用相同規則,就應該對應同樣的範圍。
- 純標點輸入。"!!!"、純空白字串以及空輸入,都會從檢查工具得到錯誤回傳,因為在標準化後沒有任何字母或數字存活下來。一個把所有字元都去除、然後比較兩個空字串的 Java 方法,會錯誤地將這些判定為迴文。
比較主要的 Java 做法
每一種 Java 迴文模式都有不同的取捨。下表摘要了各自最出色的地方,讓你能為自己的程式碼選擇合適的切入點。
| 做法 | 最適合 | 會配置字串嗎? | 保留 Unicode 字母? |
|---|---|---|---|
| 整數算術反轉 | 純正數、效能熱點 | 否 | 不適用(僅限數字) |
| 對清理過的 String 使用 StringBuilder.reverse() | 短小的混合輸入、易讀的程式碼 | 是(兩個 String) | 僅當正則表達式包含時 |
| 使用 char 陣列的雙指標走訪 | 對記憶體敏感的程式碼、無配置 | 否 | 僅當判斷式包含時 |
| IntStream / 函式式管線 | 表達力強的單行寫法、平行風格 | 是(boxed 字元) | 僅當過濾器包含時 |
整數算術版本對於一個明確命名為 isPalindromeNumber 的方法來說,是最安全的預設選擇。任何混用字母、腔調字母或標點的內容,都應該歸入以字串為基礎、並在 docstring 中明確說明標準化規則的方法。
當檢查工具的判斷與你的 Java 輸出不同時
不一致就是一種資訊,而不是 bug。它幾乎總是指出三種規則差異之一:大小寫處理、保留的字元集,或標準化形式。檢查工具明確使用固定的英文地區設定進行小寫轉換、進行 Unicode NFKC 標準化,且只保留 Unicode Letter 或 Number 碼位,同時忽略空白、標點、符號和表情符號。如果你的 Java 正則表達式是 [A-Za-z0-9],它只會匹配檢查工具所保留的一個子集 — 只有 ASCII 字母和數字 — 因此在 "Été" 上會產生不一致,因為 É 在比較前就被移除了。
如果某個特定的挑戰題或面試題目把迴文定義為嚴格的逐字元相等,請依照該定義,而不是檢查工具的預設。這個工具刻意公開它的標準化預覽,正是為了讓規則可以被審查;你可以透過呼叫 Normalizer.normalize(input, Normalizer.Form.NFKC)、過濾掉 Character.getType 既不傳回 LETTER 也不傳回 NUMBER 的字元、以 Locale.ROOT 進行小寫轉換,並將結果與其反轉進行比較,在 Java 中重現同樣的比較。
對於任何最多一百萬個 Unicode 碼點的輸入,這個比較會在瀏覽器中本機執行,不需帳號或上傳,因此能快速地反覆測試邊界情況。請把檢查工具視為其自身規則下的確定性神諭,而非通用的裁判 — 只要你的 Java 實作共用同一份已記載的標準化規則,它們就會與它對齊。