5. 最长回文子串
题目
给你一个字符串 s,找到 s 中最长的回文子串。
https://leetcode.cn/problems/longest-palindromic-substring/
这个解答方法怎么想到的?
其实官方的解答已经说的很好了,但并没有说明是怎么想到的,我在这里想谈谈自己的理解。
动态规划的本质就是状态转换方程,即我们只要找到不同状态之间的关系,就能够破题。那么我们需要关心的就是如何找到这样一个状态转换方程,我认为找到主体的关键属性就是答案
对于这道题,主体就是"回文子串",它有两个特征:
1 字符串
2 回文
其中字符串的关键属性就是长度,而回文本身就是关键属性
随着长度的变化,字符串也在变化,我们要做的就是找到长度的变化与回文这一特征的联系
到了这一步,可以自己举一些例子,例子就是基于字符串长度的变化:
ababa->bab
aa->caac
可以看到,对于一个回文串来说,不论是去掉两端的字母,还是在两端加上相同的字母,得到的结果依旧还是回文串。而这就是我们建立状态转换方程的依据
假设s代表字符串,i代表子串的开始位置,j代表子串的结束位置,dp[i][j]表示从i到j的字符串是否为回文串,那么:
if(s[i]==s[j]){
dp[i][j]=dp[i+1][j-1];
}
翻译过来就是,如果i,j位置的字母相同,那么i到j这一子串的状态(是否回文)与去掉头尾后的i+1到j-1的子串状态相同
到此,我们解体的主体思路就成功诞生了!
题解
class Solution {
public:
string longestPalindrome(string s) {
int len=s.length();
int maxlen=1,begin=0;
if(len<2){
return s;
}
int dp[len][len];
for(int i=0;i<len;i++){
dp[i][i] = 1;
}
for(int L=2;L<=len;L++){
for(int i=0;i<len;i++){
int j=L+i-1; // j-i+1=L
if(j>=len){ // 这步一定要有,防止j出界
break;
}
if(s[i]!=s[j]){
dp[i][j]=0;
}
else{
if(j-i+1<4){ // len = 1 or 2 or 3
dp[i][j]=1;
}
else{
dp[i][j]=dp[i+1][j-1];
}
}
if(dp[i][j]&&j-i+1>maxlen){ // 注意判断dp[i][j]是否为1
begin=i;
maxlen=j-i+1;
}
}
}
return s.substr(begin,maxlen);
}
};