题目描述:
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
思路1:
动态规划。
长度为1时,为回文串;
长度为2时,如果两字母相同,为回文串;
其他情况,如果s[i]==s[j]并且S[ i+1 : j-1 ]为回文串,那么s[ i : j]为回文串。
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
vector<vector<int>> dp(n, vector<int>(n));
string ans;
for (int len = 0; len < n; ++len) {//子串长度
for (int i = 0; i + len < n; ++i) {//子串起始位置
int j = i + len;//子串结束位置
if (len == 0) {//长度为1时,为回文串
dp[i][j] = 1;
}
else if (len == 1) {//长度为2时,两字符相等为回文串
dp[i][j] = (s[i] == s[j]);
}
else {//如果左右两边字符相等,且i+1,j-1为回文串,那么i,j为回文串
dp[i][j] = (s[i] == s[j] && dp[i + 1][j - 1]);
}
if (dp[i][j] && len + 1 > ans.size()) {//选取最大回文串
ans = s.substr(i, len + 1);
}
}
}
return ans;
}
};
思路2:
中心扩展法。选择长度为1或者2 的回文串,向两边扩展,两边字母相同的为回文串,继续扩展。最后选择长度最长的子串。
class Solution {
public:
pair<int ,int> expand(const string& s,int left,int right){//从left,right向左右扩展,直到两边字母不再相同。
while(left>=0&&right<s.size()&&s[left]==s[right]){
--left;
++right;
}
return {left+1 , right-1};
}
string longestPalindrome(string s) {
int n = s.size();
int start=0,end=0;//回文串其实位置
for(int i=0;i<n;i++){
auto[left1,right1]=expand(s,i,i);//长度为1,开始扩展
auto[left2,right2]=expand(s,i,i+1);//长度为2,开始扩展
if(right1-left1>end-start){//选择最长的部分
end=right1;
start=left1;
}
if(right2-left2>end-start){
end=right2;
start=left2;
}
}
return s.substr(start,end-start+1);
}
};