1、问题描述
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 长度最长为1000。
示例:
输入: "babad" 输出: "bab" 注意: "aba"也是有效答案
2、问题解析
使用dp[i][j]代表从i到j最长的回文字符串的长度
如果一个字符串的首尾字符相同,并且中间的部分也是回文字符串(dp[i+1][j-1]==j-i+1)那么它也是回文字符串
这时候dp[i][j]=dp[i+1][j-1]+2;
如果不是两个字符不相同或者中间部分不是回文字符串的话,那么就在它的两个子串(dp[i+1][j],dp[i][j-1])中选择较大的那个。
3、问题记录
期间犯了三个错误:
1)没考虑字符串长度为0的情况,并且初始化最大长度biggest应该为1
2)回文字符串的判断有问题:一开始只考虑了首尾两字符相等,没有考虑剩余的子串也需要是回文字符串
3)只有dp[i][j]大于biggest的时候,才能更新biggest和begin的值
4、代码:
class Solution {
public:
string longestPalindrome(string s) {
int len = s.length();
if (len == 0)return "";
int i, j;
vector<vector<int>> dp(len, vector<int>(len));//dp[i][j]代表从i到j最长的回文字符串长度
int biggest=1, begin=0;
for (i = 0; i < len; ++i) {
dp[i][i] = 1;
}
for (i = len - 2; i >=0; --i) {
for (j = i + 1; j < len; ++j) {
if (s[j] == s[i]&&(j-i-1)==dp[i+1][j-1]) {//如果首尾两字符相同并且剩余字符长度是最大回文长度,可以判断是回文字符串
dp[i][j] = dp[i + 1][j - 1] + 2;
if(dp[i][j]>biggest){//始终记录最大的长度和起始位置
biggest= dp[i][j];
begin = i;
}
}
else {
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
return s.substr(begin, biggest);
}
};