代码随想录day60 | 动态规划P17 | ● 647. ● 516.● 动态规划总结篇

今天 结束动态规划章节 正好是60天 fighting

647. 回文子串

给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。

回文字符串 是正着读和倒过来读一样的字符串。

子字符串 是字符串中的由连续字符组成的一个序列。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

示例 1:

复制代码
输入:s = "abc"
输出:3
解释:三个回文子串: "a", "b", "c"

示例 2:

复制代码
输入:s = "aaa"
输出:6
解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"

思路

动态规划

**定义:**dp[i][j] 代表字符串在区间[i, j]上是不是回文子串 是则true 否则 false

**递推:**在确定递推公式时,就要分析如下几种情况。

整体上是两种,就是s[i]与s[j]相等,s[i]与s[j]不相等这两种。

当s[i]与s[j]不相等,那没啥好说的了,dp[i][j]一定是false。

当s[i]与s[j]相等时,这就复杂一些了,有如下三种情况

  • 情况一:下标i 与 j相同,同一个字符例如a,当然是回文子串
  • 情况二:下标i 与 j相差为1,例如aa,也是回文子串
  • 情况三:下标:i 与 j相差大于1的时候,例如cabac,此时s[i]与s[j]已经相同了,我们看i到j区间是不是回文子串就看aba是不是回文就可以了,那么aba的区间就是 i+1 与 j-1区间,这个区间是不是回文就看dp[i + 1][j - 1]是否为true。

**初始化:**全false即可

**遍历顺序:**注意到 dp[i][j] 在情况三由 其左下角的 dp[i + 1][j - 1]决定 那么遍历要从下往上 从左往右

贪心

首先确定回文串,就是找中心然后向两边扩散看是不是对称的就可以了。

在遍历中心点的时候,要注意中心点有两种情况

一个元素可以作为中心点,两个元素也可以作为中心点。

代码

动态规划

java 复制代码
class Solution {
    public int countSubstrings(String s) {
        //dp[i][j] 代表 字符串中[i, j]区间的子串是否为回文串
        boolean [][] dp = new boolean [s.length()][s.length()];

        int num = 0;
        for(int i = s.length()-1 ; i >= 0; i--){
            for(int j = i; j < s.length();j++){
                if(s.charAt(i) == s.charAt(j)){
                     if(j - i <= 1){//情况一与情况二
                         dp[i][j] = true;
                         num++;
                     }else{
                         //情况三
                         dp[i][j] = dp[i+1][j-1];
                         if(dp[i][j]) num ++;
                     }
                }else{
                    dp[i][j] = false;
                }
            }
        }
        return num;
    }
}

贪心

java 复制代码
class Solution {
    public int countSubstrings(String s) {
        //确定回文串,就是找中心然后向两边扩散看是不是对称的就可以了。
        int res = 0;
        for (int i = 0; i < s.length(); i++) {
            //遍历每个字符作为中心点
            res += getNum(s, i, i, s.length());
            res += getNum(s, i, i + 1, s.length());
        }
        return res;
    }

    public int getNum(String s, int i, int j, int len) {
        int res = 0;
        while (i >= 0 && j < len && s.charAt(i) == s.charAt(j)) {
            //向两边扩散
            i--;
            j++;
            res++;
        }
        return res;
    }

}

516.最长回文子序列

给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

示例 1:

复制代码
输入:s = "bbbab"
输出:4
解释:一个可能的最长回文子序列为 "bbbb" 。

示例 2:

复制代码
输入:s = "cbbd"
输出:2
解释:一个可能的最长回文子序列为 "bb" 。

思路

上一题求的是回文子串,而本题要求的是回文子序列, 要搞清楚这两者之间的区别。

回文子串是要连续的,回文子序列不是连续的! 回文子串,回文子序列都是动态规划经典题目。

定义:dp[i][j]:字符串s在[i, j]范围内最长的回文子序列的长度为dp[i][j]

递推:

在判断回文子串的题目中,关键逻辑就是看s[i]与s[j]是否相同。

如果s[i]与s[j]相同,那么dp[i][j] = dp[i + 1][j - 1] + 2;

如果s[i]与s[j]不相同,说明s[i]和s[j]的同时加入 并不能增加[i,j]区间回文子序列的长度,那么分别加入s[i]、s[j]看看哪一个可以组成最长的回文子序列。

加入s[j]的回文子序列长度为dp[i + 1][j]。

加入s[i]的回文子序列长度为dp[i][j - 1]。

那么dp[i][j]一定是取最大的,即:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);

**初始化:**根据dp定义 单个字符的最长回文子序列长度为1 那么斜向初始化为1

遍历顺序:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]); 所以dp[i][j] 与 其左下角元素有关

遍历从下到上 从左到右

代码

java 复制代码
class Solution {
    public int longestPalindromeSubseq(String s) {
        //dp[i][j]:字符串s在[i, j]范围内最长的回文子序列的长度为dp[i][j]。
        int [][] dp = new int [s.length()][s.length()];
        for(int i = 0; i<s.length(); i++){
            dp[i][i] = 1;
        }

        for(int i = s.length()-1; i>=0; i--){
//            System.out.println("i=" + i);
            //注意这里j初始化为 i + 1 防止出现越界问题
            for(int j = i + 1; j<s.length(); j++){
//                System.out.println("j=" + j);
                if(s.charAt(i) == s.charAt(j)){
                    dp[i][j] = dp[i+1][j-1] + 2;
                }else{
                    dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1]);
                }
            }
        }
        return dp[0][s.length()-1];
    }
}

动态规划总结篇

代码随想录 (programmercarl.com)

相关推荐
手握风云-35 分钟前
Spring AI:让大模型住进 Spring 生态(三)
java·后端·spring
深邃-2 小时前
【数据结构与算法】-二叉树(2):实现顺序结构二叉树(堆的实现),向上调整算法,向下调整算法,堆排序,TOP-K问题
数据结构·算法·二叉树·排序算法·堆排序··top-k
咸鱼2.02 小时前
【java入门到放弃】Dubbo
java·开发语言·dubbo
We་ct5 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·javascript·算法·leetcode·typescript
JAVA面经实录9178 小时前
Java企业级工程化·终极完整版背诵手册(无遗漏、全覆盖、面试+落地通用)
java·开发语言·面试
王老师青少年编程8 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮9 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
天疆说9 小时前
【哈密顿力学】深入解读航天器交会最优控制中的Hamilton函数
人工智能·算法·机器学习
许彰午10 小时前
CacheSQL(二):主从复制——OpLog 环形缓冲区与故障自动恢复
java·数据库·缓存
wuweijianlove10 小时前
关于算法设计中的代价函数优化与约束求解的技术7
算法