題目:給定字符串 S(長度 ≤ 1000),找出最長回文子串,保證唯一解。
難度:Medium
核心思路:回文中心對稱特性 → 枚舉所有可能中心 → 向兩側擴展 → 記錄最長。
"aba",中心為字符 'b'"abba",中心為 'b'|'b' 間隙遍歷每個字符位置 i,同時檢查 (i, i) 與 (i, i+1) 兩種中心。
當遍歷至後半段,理論最大可能長度 2 * (n - 1 - i) + 1 < 當前最長長度時,直接 break,減少無效循環。
char[] 而非 String.split(""),避免首位空串且 O(1) 訪問left >= 0 && right < len 防越界class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() < 2) return s;
char[] arr = s.toCharArray();
int n = arr.length;
int maxLen = 0, start = 0;
for (int i = 0; i < n; i++) {
// 提前終止:剩餘字符即使全對稱也超不過當前最長
if (i > (n - 1) / 2 && 2 * (n - 1 - i) + 1 < maxLen) break;
int len1 = expand(arr, i, i); // 單中心
int len2 = expand(arr, i, i + 1); // 雙中心
if (len1 > maxLen || len2 > maxLen) {
if (len1 > len2) {
maxLen = len1;
start = i - (len1 - 1) / 2;
} else {
maxLen = len2;
start = i + 1 - len2 / 2;
}
}
}
return s.substring(start, start + maxLen);
}
// 從 (l, r) 向兩側擴展,返回回文長度
private int expand(char[] arr, int l, int r) {
while (l >= 0 && r < arr.length && arr[l] == arr[r]) {
l--; r++;
}
return r - l - 1; // 退出時多擴展一步,需減 1
}
}
| 指標 | 複雜度 | 說明 |
|---|---|---|
| 時間 | O(n²) | n 個中心 × 平均 O(n) 擴展;最壞情況全同字符串 "aaaaa..." |
| 空間 | O(1) | 僅使用常數額外變量,無 DP 表或 Manacher 輔助數組 |
利用回文對稱性復用已計算信息,線性時間求解。代碼較複雜,面試中中心擴展法通常足夠,但理解 Manacher 核心思想(維護最右邊界 R、中心 C、鏡像位置)是進階必修課。
@Test
public void test() {
Solution sol = new Solution();
assertEquals("cbaabc", sol.longestPalindrome("cabcbaabcaa"));
assertEquals("a", sol.longestPalindrome("a"));
assertEquals("bb", sol.longestPalindrome("bb"));
assertEquals("aba", sol.longestPalindrome("babad")); // 或 "bab"
assertEquals("ccc", sol.longestPalindrome("ccc"));
}
String.split("") 產生 String[] → 首元素為空串、內存開銷大、訪問慢ArrayIndexOutOfBoundsExceptionchar[] + 雙指針擴展 + 提前終止 = 簡潔高效「中心擴展法是回文類問題的通用模板:枚舉中心 → 擴展驗證 → 更新答案。掌握它,LeetCode 647、516 等題迎刃而解。」