• 代码随想录算法训练营第53天 | ● 1143.最长公共子序列 ● 1035.不相交的线 ● 53. 最大子序和


    文章目录


    前言

    动态规划


    一、1143.最长公共子序列

    1. 确定dp数组(dp table)以及下标的含义

    dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]

    有同学会问:为什么要定义长度为[0, i - 1]的字符串text1,定义为长度为[0, i]的字符串text1不香么?

    这样定义是为了后面代码实现方便,如果非要定义为长度为[0, i]的字符串text1也可以

    1. 确定递推公式

    主要就是两大情况: text1[i - 1] 与 text2[j - 1]相同,text1[i - 1] 与 text2[j - 1]不相同

    如果text1[i - 1] 与 text2[j - 1]相同,那么找到了一个公共元素,所以dp[i][j] = dp[i - 1][j - 1] + 1;

    如果text1[i - 1] 与 text2[j - 1]不相同,那就看看text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列,取最大的。

    即:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);

    1. dp数组如何初始化

    先看看dp[i][0]应该是多少呢?

    test1[0, i-1]和空串的最长公共子序列自然是0,所以dp[i][0] = 0;

    同理dp[0][j]也是0。

    其他下标都是随着递推公式逐步覆盖,初始为多少都可以,那么就统一初始为0。

    1. 确定遍历顺序

    从递推公式,可以看出,有三个方向可以推出dp[i][j],如图:

    举例推导dp数组;

    1. class Solution {
    2. public int longestCommonSubsequence(String text1, String text2) {
    3. int[][] dp = new int[text1.length()+1][text2.length()+1];
    4. for(int i = 1;i<=text1.length();i++){
    5. char char1 = text1.charAt(i-1);
    6. for(int j = 1;j<=text2.length();j++){
    7. char char2 = text2.charAt(j-1);
    8. if(char1 == char2){
    9. dp[i][j] = dp[i-1][j-1] + 1;
    10. }else{
    11. dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
    12. }
    13. }
    14. }
    15. return dp[text1.length()][text2.length()];
    16. }
    17. }

    二、1035.不相交的线

    上一题的变种题目。

    下面的代码,是用的循环得出max的方法;但,事实上,dp数组表示的是“dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]”;所以直接return dp[len1][len2]。

    1. class Solution {
    2. public int maxUncrossedLines(int[] nums1, int[] nums2) {
    3. int len1 = nums1.length;
    4. int len2 = nums2.length;
    5. int res = 0;
    6. int[][] dp = new int[len1+1][len2+1];
    7. for(int i =1;i<=len1;i++){
    8. for(int j=1;j<=len2;j++){
    9. if(nums1[i-1] == nums2[j-1]){
    10. dp[i][j] = dp[i-1][j-1]+1;
    11. }else{
    12. dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
    13. }
    14. res = Math.max(res,dp[i][j]);
    15. }
    16. }
    17. return res;
    18. }
    19. }

    三、53. 最大子序和

    动规五部曲如下:

    1. 确定dp数组(dp table)以及下标的含义

    dp[i]:包括下标i(以nums[i]为结尾)的最大连续子序列和为dp[i]

    1. 确定递推公式

    dp[i]只有两个方向可以推出来:

    • dp[i - 1] + nums[i],即:nums[i]加入当前连续子序列和
    • nums[i],即:从头开始计算当前连续子序列和

    一定是取最大的,所以dp[i] = max(dp[i - 1] + nums[i], nums[i]);

    1. dp数组如何初始化

    从递推公式可以看出来dp[i]是依赖于dp[i - 1]的状态,dp[0]就是递推公式的基础。

    dp[0]应该是多少呢?

    根据dp[i]的定义,很明显dp[0]应为nums[0]即dp[0] = nums[0]。

    1. 确定遍历顺序

    递推公式中dp[i]依赖于dp[i - 1]的状态,需要从前向后遍历。

    1. 举例推导dp数组

     

    1. class Solution{
    2. public static int maxSubArray(int[] nums) {
    3. if(nums.length == 0){
    4. return 0;
    5. }
    6. int res = nums[0];
    7. int[] dp = new int[nums.length];
    8. dp[0] = nums[0];
    9. for(int i =1;i
    10. dp[i] = Math.max(dp[i-1] + nums[i],nums[i]);
    11. res = res >dp[i] ? res:dp[i];
    12. }
    13. return res;
    14. }
    15. }


    总结

    动态规划;

  • 相关阅读:
    湾区新势力 智创大未来,数说故事大湾区总部一周年暨琴澳战略发布会成功举办
    【SpringCloud】一、SpringCloud介绍
    BIM系统平台建设及实施方案
    C++基础与深度解析 | 输入与输出 | 文件与内存操作 | 流的状态、定位与同步
    物理层
    redis集群相关
    深入理解 Python 虚拟机:复数(complex)的实现原理及源码剖析
    ClickHouse(05)ClickHouse数据类型详解
    炙手可热的ZNS SSD将会为数据中心带来什么?
    微服务实战系列之加密RSA
  • 原文地址:https://blog.csdn.net/m0_51671538/article/details/132919871