LeetCode.5--最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

本文章使用动态规划的方法解决该问题

动态规划问题要解决两个关键点:
一是初始化,初始化用来确定动态规划的起点,也是非常重要的。
二是状态转移。状态转移确定动态规划过程中的状态更新公式。

下面来用动态规划的思想具体分析一下该问题。
首先明确回文字符串的含义
回文字符串: 正着读和反着读都一样的字符串,单个字符也是回文字符串

根据回文字符串的含义,我们可以得出一些初始信息
  • 单个字符为回文子串
  • 两个字符相同为回文子串
寻找状态转移的信息

根据回文字符串的特性,即回文字符串左右两端加上相同的字符组成的新字符串也是回文字符串,具体描述如下

x b x 为 回 文 字 符 串 , 则 y x b x y 也 是 回 文 字 符 串 xbx为回文字符串,则 yxbxy也是回文字符串 xbxyxbxy
即回文字符串左右两端加上相同字符也是回文字符串。

利用上述的信息可以得出当 字符串左右两端字符相等并且去掉两端字符的字符串为回文字符串,则判断字符为回文字符串。

Alt

d p ( i , j ) 存 放 以 i 开 始 , 以 j 结 束 的 字 符 串 的 状 态 , t r u e 表 示 为 回 文 , f a l s e 表 示 不 是 回 文 dp(i,j)存放以i开始,以j结束的字符串的状态,true表示为回文,false表示不是回文 dp(i,j)ijtruefalse

则初始条件可以写为
d p ( i , i ) = t r u e dp(i,i)=true dp(i,i)=true d p ( i , i + 1 ) = t r u e , i f s ( i ) = s ( j ) dp(i,i+1)=true,if s(i)=s(j) dp(i,i+1)=true,ifs(i)=s(j)

现在可以写出状态转移公式
在这里插入图片描述
这里需要保证开始位置要小于结束位置,则有
j − 1 > i + 1 , 即 子 串 长 度 j − i > 2 j-1>i+1,即子串长度j-i>2 j1>i+1,ji>2
因此没有将第二条初始化条件写入状态转移公式。
状态转移如下所示
状态更新图
行代表j,列代表i,true代表是回文子串

下面是程序设计

//时间复杂度:使用单循环初始化,双循环+判断进行状态更新,时间复杂度为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的每个元素记录当前长度下回文子串开始的位置。

注:对于最长回文子串问题还有其他解法,比如暴力搜索、中心扩展、马拉车等参见其他解答

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值