给你一个字符串 s,找到 s 中最长的回文子串。 如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
解:
对于一个字符串而言,如果它是回文串,并且长度大于2,那么将他的收尾两个字母去掉之后一定是仍然是一个回文串。例如ababa 如果已知bab是回文串,那么ababa一定是回文串,因为首尾字母都是a
因此,可以使用动态规划解决本体,使用P(i,j)表示字符串s的第i到j个字母组成的串s[i:j] 是否为回文串
这里包括两种可能性
- s[i,j]本身不是一个回文串
- i>j,此时s[i,j]不合法
那么我们就可以写出动态规划的状态转移方程
也就是说,只有s[i+1:j-1]是回文串,并且s的第i和j个字母相同时,s[i:j]才会是回文串
所提到的都是建立在子串长度大于2的前提之上的,还需要考虑动态规划中的边界条件,也就是子串的长度为1或者2.对于长度为1的子串,它显然是一个回文串;对于长度为2的子串,只要它的两个字母相同,他就是一个回文串。因此我们可以写出动态规划的边界条件。
根据这个思路我们可以完成动态规划,最终的答案即为所有P(i,j)=true 中的j-i+1(子串长度)的最大值
需要注意的是,在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,因此需要注意动态规划的循环顺序。
动态规划法 C++
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size();//如果小于2的话直接返回
if(n<2){
return s;
}
int maxLen =1;
int begin=0;
vector<vector<int>> dp(n,vector<int>(n));// dp[i][j] 表示 s[i..j] 是否是回文串
//声明了一个名为dp的二维动态数组,它有n行n列,每个元素都是int类型。
//vector<int>(n) 部分创建一个包含 n 个元素的一维整数向量,并将每个元素初始化为零。(列) vector<vector<int>> 部分创建一个包含 n 行的二维向量,其中每一行都是由 vector<int>(n) 创建的一维向量的副本。
for(int i=0;i<n;i++)
{
dp[i][i]=true;
}
//递推开始
//首先枚举子串长度
for(int L=2;L<=n;L++)
{
for(int i=0;i<n;i++)//枚举左边界,左边界的上限设置可以宽松一些
{
int j=L+i-1;//由L和i可以确定右边边界,也就是j-i+1=L
if(j>=n)//如果右边界越界,那么直接退出循环
{
break;
}
if(s[i]!=s[j])
{
dp[i][j]=false;
}else{
if(j-i<3)
{
dp[i][j]=true;
}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);
//substr() 方法用于提取字符串的一部分,从指定的索引 (begin) 开始,并持续指定的字符数 (maxLen)。
}
};