今天就按照順序講我們的下一題(第五題)
給予一字串 s, 回傳在 s中可找到最長的回文子字串
以下是具體的解題步驟,使用 Markdown 語法書寫:
問題轉換
利用動態規劃表 DP[i][j]
來表示字串 s[i..j]
是否是回文,最終目標是找到字串中最長的回文子串。
DP[i][j] == true
,則表示 s[i..j]
是回文子串。DP[i][j] == false
,則 s[i..j]
不是回文子串。特殊情況處理
初始化動態規劃表
DP[i][i] = true
,代表所有單個字符的子串都是回文。DP[i][i+1] = true
。遞迴檢查長度大於 2 的子串
s[i..j]
,如果 s[i] == s[j]
且子串 s[i+1..j-1]
是回文(即 DP[i+1][j-1] == true
),則可以確定 s[i..j]
是回文,更新 DP[i][j] = true
。start
和最大長度 maxLen
。更新結果
返回結果
s.substr(start, maxLen)
根據記錄的 start
和 maxLen
返回最長回文子串。這樣可以避免手動構建回文字串。class Solution {
public:
string longestPalindrome(string s) {
int size = s.size();
if (size <= 1) return s;
// 動態規劃表初始化,DP[i][j] 表示 s[i..j] 是否是回文
vector<vector<bool>> DP(size, vector<bool>(size, false));
int maxLen = 1; // 最長回文子串的長度
int start = 0; // 最長回文子串的起始位置
// 單個字符的子串一定是回文
for (int i = 0; i < size; i++) {
DP[i][i] = true;
}
// 檢查長度為2的子串是否是回文
for (int i = 0; i < size - 1; i++) {
if (s[i] == s[i + 1]) {
DP[i][i + 1] = true;
start = i;
maxLen = 2;
}
}
// 檢查長度大於2的子串
for (int len = 3; len <= size; len++) { // len 是子串的長度
for (int i = 0; i <= size - len; i++) {
int j = i + len - 1; // j 是子串的結尾
// 若 s[i] == s[j] 且中間的子串是回文,則 s[i..j] 是回文
if (s[i] == s[j] && DP[i + 1][j - 1]) {
DP[i][j] = true;
if (len > maxLen) {
start = i;
maxLen = len;
}
}
}
}
// 回傳最長回文子串
return s.substr(start, maxLen);
}
};