动态规划系列之《最长回文子串》

动态规划题目难度比较高,要完全掌握不是一件容易的事情,因此先从一些经典题型开始,刷的次数多了,慢慢就能抓住动态规划的牛鼻子了,话休絮烦,直接开冲!

力扣No.5: 最长回文字串

问题描述

问类似 “cbaab”这样一个字符串,最长的回文子串是哪个?

思考过程

很容易想到一种O(n2)的解法,逐个遍历所有的子串,挨个判定是否回文。毫无疑问会超时,超时的原因是重复判断了很多子串是否是回文,例如当判断子串 “aa” 的时候,我们对其做出了判断是回文串,然而当轮到子串 “baab” 的时候,利用双指针方法判断时,左右字符相同,因此接着判定“aa”,这样又对“aa”做了一次重复判定,浪费了效率。因此我们需要做的就是直接利用一些稍短子串的判断结果,辅助判断较长的子串

1. 定义状态

设定二维数组dp[i][j],表示子串s[i,…,j]是否是回文串

2. 状态转移

这部分是动态规划的核心,也是最难想的部分,一言以蔽之就是如何将一个现在的问题,转移到我们之前已经解决的一个子问题上。直接上结论:
dp[i][j] = (s[i]==s[j]) && dp[i+1][j-1]

上面转移公式的可以这么解读:一个子串 s[i…j],如果首尾两个字符不等,肯定不是回文串,如果首尾相等,就判定除去首尾两个字符剩下的子串,若是回文串,则整个s[i…j]就是回文串。

3. 确定初始状态

cbaab 为例,输入数组长度为5,则5×5的二维数组dp,我们只需要填充对角线上方的表格内容(因为dp[i][j必须满足i<=j),并且对角线dp[i][i]都为真

\01234
0T
1T
2T
3T
4T
4. 填表(输出)

这一步的难点在于,我们要按照怎样的顺序填表,一开始的想法是逐行去填,但是当判定dp[0][3]的时候,dp[1][2]还没有填到,无法辅助我们填表。这里正确的做法应该是按照子串的长度来填,联想到第三步中,我们把所有的对角线初始化为真,其实这一步就是把所有的长度为1的子串判定,因此接下来就要判定所有的长度为2,3…m的子串。

  • 判定所有长度为2的子串,
\01234
0TF
1TF
2TT
3TF
4T
  • 判定所有长度为3的子串,
\01234
0TFF
1TFF
2TTF
3TF
4T
  • 判定所有长度为4的子串,
\01234
0TFFF
1TFFT
2TTF
3TF
4T
  • 判定所有长度为5的子串,
\01234
0TFFFF
1TFFT
2TTF
3TF
4T
5. 得出结论

填表的时候,我们只需记录回文串的最终长度和开始序号就行了,例如这里是长度为4,从1开始的子串 "baab"


最后附上代码

class Solution {
public:
    string longestPalindrome(string s) 
    {
        int m = s.size();
        if( m <= 1) return s;
        vector<vector<int>> dp(m, vector<int>(m, 0));
        // 确定初始状态,所有的单个字符都是回文字串
        for(int i = 0; i < m; i++)
            dp[i][i] = 1;
        int begin = 0, ans_len = 1;
        // 判断所有长度2到m的字串
        for(int len = 2; len <= m; len++)
        {
            for(int i = 0; i + len <= m; i++)
            {
                if(len <= 3) // 小于等于3的子串,直接判断首尾是否想等
                    dp[i][i + len - 1] = s[i] == s[i + len-1] ? 1 : 0;
                else // 长度大于3的子串,判断首尾以及dp[i+1][j-1]
                    dp[i][i + len - 1] = s[i] == s[i + len - 1] && dp[i + 1][i + len - 2] ? 1 : 0;      
                if(dp[i][i + len - 1] && len > ans_len)
                {
                    begin = i;
                    ans_len = len;
                } 
            }
        }
        return s.substr(begin, ans_len);
    }
};

这里的时间和空间复杂度是O(n2),也并非是ac的最优解,重要的是动态规划的思考过程!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值