动态规划
1.确定DP数组以及下标含义
2.确定递推公式(状态转移方程)
3.初始化
4.注意遍历顺序(状态由较短回文串向较长回文串转移)即填表时参考的值不能还未计算——先计算dp[ i + 1 ][ j - 1 ]再计算dp[ i ][ j ]
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size();
//先考虑边界条件
//初始值
if(n==1) return s;
if(n==2&&s[0]==s[1]) return s;
int maxlen=0,begin=0;
//确定DP数组,下标含义:表示区间范围内[i,j]子串是否是回文串
vector<vector<int>> dp(n, vector<int>(n,1));
//填表顺序非常关键
//在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的
//因此一定要注意动态规划的循环顺序
for(int i=n-1;i>=0;i--){
for(int j=i;j<n;j++){
//判定规则,状态转移方程
if(s[i]!=s[j]){
dp[i][j]=0;
}else{
if(j-i<3){
dp[i][j]=1;
}else{
dp[i][j]=dp[i+1][j-1];
}
}
//更新,只需要记录起点和长度
if(dp[i][j]&&j-i+1>maxlen){
maxlen=j-i+1;
begin=i;
}
}
}
return s.substr(begin,maxlen);
}
};
中心扩散法
class Solution {
public:
int maxLength=0;
int start=0,end=0;
string longestPalindrome(string s) {
//中心扩散法
int n=s.size();
if(n==0||n==1)return s;
//遍历每一个位置当作中心位
for(int i=0;i<n;i++){
expandCenter(s,i,i);//len_odd
expandCenter(s,i,i+1);//len_even
}
return s.substr(start,maxLength);
}
//s输入的字符串 left起始左边界 right起始右边界 返回值 回文串长度
int expandCenter(string s,int left,int right){
//找到字符串可能的回文子串中心
//奇数:具体字符
//偶数:两个字符中间的空隙
while (left >= 0 && right < s.size() && s[left] == s[right]){
if (right - left + 1 > maxLength) {
start = left;
end = right;
maxLength = right - left + 1;
}
left--;
right++;
}
return maxLength;
}
};