給定字符串 S(長度 ≤ 1000),找出最長回文子串。本文展示暴力枚舉解法(會超時),並指明優化方向。
public class Solution {
public String longestPalindrome(String s) {
if (s.length() <= 1) return s;
String longest = "";
int maxLen = 0;
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
// 剪枝:剩餘長度不足以超過當前最長
if (chars.length - i + 1 <= maxLen) return longest;
for (int j = chars.length - 1; j > i; j--) {
if (chars[i] == chars[j]) {
String sub = s.substring(i, j + 1);
int len = j - i + 1;
if (isPalindrome(sub) && len > maxLen) {
longest = sub;
maxLen = len;
break; // 同起點只需最長回文
}
}
}
}
return longest;
}
private boolean isPalindrome(String str) {
char[] c = str.toCharArray();
int i = 0, j = c.length - 1;
while (i <= j) {
if (c[i] != c[j]) return false;
i++; j--;
}
return true;
}
}
n=1000 時約 10⁹ 次操作,必超時。
| 算法 | 時間 | 空間 | 核心思想 |
|---|---|---|---|
| 中心擴展法 | O(n²) | O(1) | 以每字符/字符間隙為中心向兩側擴展 |
| 動態規劃 | O(n²) | O(n²) | dp[i][j] 記錄子串是否回文 |
| Manacher 算法 | O(n) | O(n) | 利用回文對稱性避免重複計算 |
public String longestPalindrome(String s) {
if (s == null || s.length() < 2) return s;
int start = 0, end = 0;
for (int i = 0; i < s.length(); i++) {
int len1 = expand(s, i, i); // 奇數長度
int len2 = expand(s, i, i + 1); // 偶數長度
int len = Math.max(len1, len2);
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substring(start, end + 1);
}
private int expand(String s, int left, int right) {
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
left--; right++;
}
return right - left - 1;
}