力扣Hot100-5最长回文子串【动规五步法】

力扣Hot100-5 最长回文子串

全部刷题与学习记录

【C++刷题学习笔记目录】

原题目

题目地址:5. 最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"
输出:"bb"

考查知识点

动态递归

好的解法

以往动态递归的题目中,题目给出一维环境(如斐波那契数),dp数组就是一维数组,题目是二维环境(矩阵路径),dp数组就是二维数组

这道题解剑走偏锋,环境是一维(字符串),dp数组却是二维的

对于动态规划,先用【动规五步法】来分析:

1、确定dp数组及下标含义dp[i][j]表示字符串s的第i个字母到第j个字母组成的子串;dp[i] [j] = 1表示该子串是回文串,值为0表示其他情况(有两种可能,s[i] [j]不是回文串 || i > j, 此时s[i] [j]不合法)

2、确定递推公式:一个回文串必然是关于中心对称的,只有 s[i+1:j-1](更小范围上的dp[i] [j])是回文串,并且 s 的第 i 和 j个字母相同时,s[i:j]才会是回文串。递推公式为:dp[i][j] = (dp[i+1][j-1] && s[i] == s[j])

3、确定dp数组初始化:当回文串长度为0(代表只有一个字符)时,也算是特殊的回文串,dp[i] [j] = 1;当回文串长度是1(代表有两个字符)时,只要这两个字符相等,那么也是回文串dp[i] [j] = 1

4、确定dp数组遍历顺序:题解中使用的遍历顺序很新,一般来说二维dp数组都是从左到右、从上到下来遍历,但是字符串是一位的,在一维环境中使用二维dp数组,这里就给出了一种以前没见过的遍历顺序。先遍历子串长度,再遍历子串左起始位置。

5、举例推导dp数组

跳过

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        // dp[left][right]标记从i到j是否是字串
        vector<vector<int>> dp(n, vector<int>(n));
        string ans;
        // length表示判断的字串的长度
        // left表示字串的左边起始位置
        // right表示字串的右边起始位置
        for(int length = 0; length < n; length++){
            for(int left = 0; left + length < n; left++){
                int right = left + length;
                // 即字符串长度为1时,矩阵对角线
                if(length == 0) dp[left][right] = 1;
                    // 字符串长度为2的时候,只需判断两者是否相等
                else if(length == 1) dp[left][right] = (s[left] == s[right]);
                else{  // 字符串长度大于等于3之后
                    // 其是否是回文串取决于当前left和right及更小一号的字符串
                    // 更新参考值为矩阵的左下方
                    dp[left][right] = (s[left] == s[right] && dp[left + 1][right - 1]);
                }
                // 如果当前left位置到right位置的字串能够构成回文串,并且现在长度+1后大于之前记忆中的子回文串的长度,那么更新回文串!
                // 这里也可以优化成记录起始位置和长度的两个int,返回时再截取
                if(dp[left][right] && (length + 1) > ans.size()){
                    ans = s.substr(left, length + 1);
                }
            }
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值