给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
本文章使用动态规划的方法解决该问题
动态规划问题要解决两个关键点:
一是初始化,初始化用来确定动态规划的起点,也是非常重要的。
二是状态转移。状态转移确定动态规划过程中的状态更新公式。
下面来用动态规划的思想具体分析一下该问题。
首先明确回文字符串的含义
回文字符串: 正着读和反着读都一样的字符串,单个字符也是回文字符串
根据回文字符串的含义,我们可以得出一些初始信息
- 单个字符为回文子串
- 两个字符相同为回文子串
寻找状态转移的信息
根据回文字符串的特性,即回文字符串左右两端加上相同的字符组成的新字符串也是回文字符串,具体描述如下
即回文字符串左右两端加上相同字符也是回文字符串。
利用上述的信息可以得出当 字符串左右两端字符相等并且去掉两端字符的字符串为回文字符串,则判断字符为回文字符串。
则初始条件可以写为
现在可以写出状态转移公式
这里需要保证开始位置要小于结束位置,则有
因此没有将第二条初始化条件写入状态转移公式。
状态转移如下所示
下面是程序设计
//时间复杂度:使用单循环初始化,双循环+判断进行状态更新,时间复杂度为O(n^2)
//空间复杂度 :使用n*n 的二维数组,空间复杂度为O(n^2)
class Solution {
public:
string longestPalindrome(string s) {
if(s.length()<2)
return s;
int start=0;
int len=1;
vector<vector<bool>> dp(s.length(),vector<bool>(s.length()));
for(int i=0;i<s.length()-1;i++)//初始化长度为1,2的子串
{
dp[i][i]=true;//初始化
if(s[i]==s[i+1])
{
dp[i][i+1]=true;
len=2;
start=i;//记录满足条件的最后一个子串的开始位置
}
}
for(int l=3;l<=s.length();l++)
{
for(int i=0;l+i-1<s.length();i++)
{
int j=l+i-1;//确定子串终止位置
if(s[i]==s[j]&&dp[i+1][j-1])
{
dp[i][j]=true;
len=l; //子串的长度
start=i; //最后一个子串的开始位置
}
}
}
return s.substr(start,len);
}
};
如果输入第一个最长回文子串:
使用vector数组vec代替start变量记录当前回文长度的起始位置,利用变量start_a记录每个长度回文子串的第一个起始位置,并清空vector(start_a=vec.empty()? start_a:vec[0];)
如果要输出所有符合条件的回文子串
使用数组vector>vec ,每一个长度记录vec的一个元素,vec的每个元素记录当前长度下回文子串开始的位置。
注:对于最长回文子串问题还有其他解法,比如暴力搜索、中心扩展、马拉车等参见其他解答
来源:CSDN
作者:小白的愤怒
链接:https://blog.csdn.net/qq_41689306/article/details/104671463