題目:
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
找出給定字符串的最長迴文子串,首先想到使用暴力解法,第一層循環從字符串頭遍歷到尾,第二層循環從尾部開始到頭部,第三層循環檢驗是否是迴文。這樣的話時間複雜度很高,不做一些特殊情況的判斷就會TLE,以下貼出我的代碼:
string Solution::longestPalindrome(string s) {
if (s.length() <= 1) return s;
string res = "";
int front, rear, forward;
int end;
for (int i = 0; i < (int)s.length(); i++) {
forward = 0;
front = i;
end = rear = (int)s.length() - 1;
while (front < rear) {
while (s[front] == s[rear] && front <= rear) {
front++;
rear--;
forward++;
}
/* 找到迴文並且迴文比最長的迴文要長 */
if (front >= rear && end - i + 1 > res.length()) {
res = s.substr(i, end - i + 1);
break;
}
rear = rear + forward - 1;
front = i;
end = rear;
forward = 0;
}
if (res.length() >= s.length() - i) break; // 找到最長的迴文就跳出
}
if (res == "") {
return s.substr(0,1);
}
return res;
}
很明顯,這樣做的話會有很多重複操作,浪費了時間,可以使用一個二維數組v[i][j]
記錄從i
個位置到第j
個位置的字符串是否是迴文,如果是迴文,那麼去掉子串左右兩端後仍然是迴文,利用這個概念可以設計出dp轉移方程dp[i][j+i-1] = 1 if dp[i+1][j+i-2]==1
,然後記錄子串頭尾位置即可。這樣可以把複雜度降到O(n^2)
代碼如下:
string Solution::longestPalindrome2(string s) {
if (s.length() <= 1) return s;
vector<vector<int>> dp(s.length(), vector<int>(s.length(), 0)); // dp[i][j]記錄從i到j是否爲迴文
int len = 0;
int start = 0, end = 0;
dp[0][0] = 1;
for (int i = 1; i < (int)s.length(); i++) {
dp[i][i] = 1;
dp[i][i - 1] = 1; // 子串長度爲2時,dp[i][i+1]與dp[i+1][i]同狀態
}
/* 枚舉迴文長度 */
for (int subStrLen = 1; subStrLen < s.length(); subStrLen++) {
/* 枚舉迴文開始位置 */
for (int head = 0; head + subStrLen < s.length(); head++) {
/* 迴文去掉左右端字符仍然是迴文 */
if (s[head + subStrLen] == s[head] && dp[head + 1][head + subStrLen - 1]) {
dp[head][head + subStrLen] = 1;
if (subStrLen > end - start) {
start = head;
end = start + subStrLen;
break;
}
}
}
}
return s.substr(start, end - start + 1);
}