题目:
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);
}