代码学习记录42---动态规划

随想录日记part42

t i m e : time: time 2024.04.14



主要内容:今天开始要学习动态规划的相关知识了,今天的内容主要涉及:最长递增子序列 ;最长连续递增序列 ;最长重复子数组 ;最长公共子序列;不相交的线 ;最大子序和动态规划



动态规划五部曲:
【1】.确定dp数组以及下标的含义
【2】.确定递推公式
【3】.dp数组如何初始化
【4】.确定遍历顺序
【5】.举例推导dp数组

Topic1最长递增子序列

在这里插入图片描述

思路:

接下来进行动规五步曲:
1.确定dp数组以及下标的含义:
dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度
2.确定递推公式:

//位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 + 1 的最大值。
if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);

3.dp数组如何初始化

 Arrays.fill(dp, 1);

4.确定遍历顺序
从递归公式其实已经可以看出,一定是从前向后遍历,因为dp[i],依靠dp[i - 1]的数值。
5.举例推导dp数组
输入:[0,1,0,3,2],dp数组的变化如下:
在这里插入图片描述
代码如下:

class Solution {
    public int lengthOfLIS(int[] nums) {
        int len = nums.length;
        // dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度
        int[] dp = new int[len];
        Arrays.fill(dp, 1);
        if (len == 1)
            return 1;
        dp[0] = 1;
        int max_value = 1;
        for (int i = 1; i < len; i++) {
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j])
                    dp[i] = Math.max(dp[j] + 1, dp[i]);
            }
            max_value = Math.max(max_value, dp[i]);
        }
        return max_value;
    }
}


时间复杂度 O ( n 2 ) O(n^2) O(n2)
空间复杂度 O ( n ) O(n) O(n)



Topic2最长连续递增序列

题目:
在这里插入图片描述

思路:

接下来进行动规五步曲:
1.确定dp数组以及下标的含义:
dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度
2.确定递推公式:

if(nums[i]>nums[i-1])dp[i]=dp[i-1]+1;

3.dp数组如何初始化

 Arrays.fill(dp, 1);

4.确定遍历顺序
从递归公式其实已经可以看出,一定是从前向后遍历,因为dp[i],依靠dp[i - 1]的数值。
5.举例推导dp数组
已输入nums = [1,3,5,4,7]为例,dp数组状态如下:
在这里插入图片描述

class Solution {
    public int findLengthOfLCIS(int[] nums) {
        int len = nums.length;
        int[] dp = new int[len];
        Arrays.fill(dp, 1);
        int result = 1;
        for (int i = 1; i < len; i++) {
            if (nums[i] > nums[i - 1]) {
                dp[i] = dp[i - 1] + 1;
            }
            result = Math.max(result, dp[i]);
        }
        return result;

    }
}

时间复杂度 O ( n ) O(n) O(n)
空间复杂度 O ( n ) O(n) O(n)



Topic3最长重复子数组

题目:
在这里插入图片描述

思路:

接下来进行动规五步曲:
1.确定dp数组以及下标的含义:
dp[i][j] :以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]。 (特别注意: “以下标i - 1为结尾的A” 标明一定是 以A[i-1]为结尾的字符串 )
2.确定递推公式:
根据dp[i][j]的定义,dp[i][j]的状态只能由dp[i - 1][j - 1]推导出来。即当A[i - 1] 和B[j - 1]相等的时候,dp[i][j] = dp[i - 1][j - 1] + 1;根据递推公式可以看出,遍历i 和 j 要从1开始!
3.dp数组如何初始化

 for(int i=0;i<=nums1.length;i++) dp[i][0]=0;
 for(int i=0;i<=nums2.length;i++) dp[0][i]=0;

4.确定遍历顺序
外层for循环遍历A,内层for循环遍历B。
5.举例推导dp数组
拿示例1中,A: [1,2,3,2,1],B: [3,2,1,4,7]为例,画一个dp数组的状态变化,如下:
在这里插入图片描述

class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        // dp[i][j] :以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]。 (特别注意: “以下标i -1为结尾的A” 标明一定是 以A[i-1]为结尾的字符串 )
        int[][] dp = new int[nums1.length + 1][nums2.length + 1];
        for (int i = 0; i <= nums1.length; i++)
            dp[i][0] = 0;
        for (int i = 0; i <= nums2.length; i++)
            dp[0][i] = 0;
        int result = 0;
        for (int i = 1; i < nums1.length + 1; i++) {
            for (int j = 1; j < nums2.length + 1; j++) {
                if (nums1[i - 1] == nums2[j - 1])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                result = Math.max(result, dp[i][j]);
            }
        }
        return result;

    }
}


Topic4最长公共子序列

题目:
在这里插入图片描述

思路:

接下来进行动规五步曲:
1.确定dp数组以及下标的含义:
dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]
2.确定递推公式:
主要就是两大情况:1.text1[i - 1] 与 text2[j - 1]相同 2.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]);
3.dp数组如何初始化

 for(int i=0;i<=nums1.length;i++) dp[i][0]=0;
 for(int i=0;i<=nums2.length;i++) dp[0][i]=0;

4.确定遍历顺序
外层for循环遍历A,内层for循环遍历B。
5.举例推导dp数组
以输入:text1 = “abcde”, text2 = “ace” 为例,dp状态如图:
在这里插入图片描述

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        int len1 = text1.length();
        int len2 = text2.length();
        int[][] dp = new int[len1 + 1][len2 + 1];
        for (int i = 0; i <= len1; i++)
            dp[i][0] = 0;
        for (int i = 0; i <= len2; i++)
            dp[0][i] = 0;
        int result = 0;
        for (int i = 1; i < len1 + 1; i++) {
            for (int j = 1; j < len2 + 1; j++) {
                if (text1.charAt(i - 1) == text2.charAt(j - 1))
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
                result = Math.max(result, dp[i][j]);
            }
        }
        return result;
    }
}

时间复杂度 O ( n ∗ m ) O(n*m) O(nm)
空间复杂度 O ( n ∗ m ) O(n*m) O(nm)



Topic5不相交的线

题目:
在这里插入图片描述
在这里插入图片描述

思路:

接下来进行动规五步曲:
1.确定dp数组以及下标的含义:
dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]
2.确定递推公式:
主要就是两大情况:1.text1[i - 1] 与 text2[j - 1]相同 2.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]);
3.dp数组如何初始化

 for(int i=0;i<=nums1.length;i++) dp[i][0]=0;
 for(int i=0;i<=nums2.length;i++) dp[0][i]=0;

4.确定遍历顺序
外层for循环遍历A,内层for循环遍历B。
5.举例推导dp数组

class Solution {
    public int maxUncrossedLines(int[] nums1, int[] nums2) {
        int len1 = nums1.length;
        int len2 = nums2.length;
        int[][] dp = new int[len1 + 1][len2 + 1];
        for (int i = 0; i <= len1; i++)
            dp[i][0] = 0;
        for (int i = 0; i <= len2; i++)
            dp[0][i] = 0;
        int result = 0;
        for (int i = 1; i < len1 + 1; i++) {
            for (int j = 1; j < len2 + 1; j++) {
                if (nums1[i - 1] == nums2[j - 1])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
                result = Math.max(result, dp[i][j]);
            }
        }
        return result;
    }
}

时间复杂度 O ( n ∗ m ) O(n*m) O(nm)
空间复杂度 O ( n ∗ m ) O(n*m) O(nm)



Topic6最大子序和动态规划

题目:
在这里插入图片描述

思路:

接下来进行动规五步曲:
1.确定dp数组以及下标的含义:
dp[i]:包括下标i(以nums[i]为结尾)的最大连续子序列和为dp[i]
2.确定递推公式:
dp[i]只有两个方向可以推出来:
dp[i - 1] + nums[i],即:nums[i]加入当前连续子序列和
nums[i],即:从头开始计算当前连续子序列和
一定是取最大的,所以dp[i] = max(dp[i - 1] + nums[i], nums[i]);
3.dp数组如何初始化
dp[0] = nums[0]
4.确定遍历顺序
递推公式中dp[i]依赖于dp[i - 1]的状态,需要从前向后遍历。
5.举例推导dp数组
以示例一为例,输入:nums = [-2,1,-3,4,-1,2,1,-5,4],对应的dp状态如下:
在这里插入图片描述

class Solution {
    public int maxSubArray(int[] nums) {
        int len = nums.length;
        int[] dp = new int[len];
        Arrays.fill(dp, Integer.MIN_VALUE);
        int tem;
        dp[0] = nums[0];
        if (len == 0)
            return 0;
        int result = nums[0];
        for (int i = 1; i < len; i++) {
            dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
            result = Math.max(result, dp[i]);
        }
        return result;
    }
}

时间复杂度 O ( n ) O(n) O(n)
空间复杂度 O ( n ) O(n) O(n)

相关推荐

  1. 代码学习记录36---动态规划

    2024-04-15 05:18:05       46 阅读
  2. 代码学习记录39---动态规划

    2024-04-15 05:18:05       33 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-15 05:18:05       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-15 05:18:05       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-15 05:18:05       82 阅读
  4. Python语言-面向对象

    2024-04-15 05:18:05       91 阅读

热门阅读

  1. 责任链模式学习进阶--一起学习吧之数据库

    2024-04-15 05:18:05       45 阅读
  2. RS-232、RS-422及RS-485串行数据标准的选择及使用

    2024-04-15 05:18:05       45 阅读
  3. css 太极图案例带来的收获

    2024-04-15 05:18:05       133 阅读
  4. 物联网智能仓储系统毕业设计报告

    2024-04-15 05:18:05       34 阅读
  5. 方法引用(详)

    2024-04-15 05:18:05       32 阅读
  6. 【华为OD机试C++】图片整理

    2024-04-15 05:18:05       44 阅读
  7. 4-安装并配置Grafana并导入特定的仪表板模板

    2024-04-15 05:18:05       44 阅读
  8. 未来的前端框架技术发展趋势

    2024-04-15 05:18:05       45 阅读
  9. 获取主页数据并显示流程笔记

    2024-04-15 05:18:05       142 阅读
  10. 基于单片机的智能照明控制系统设计与实现

    2024-04-15 05:18:05       33 阅读