Day55~300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组

100 阅读4分钟

摘要

本文主要介绍了LeetCode动态规划的几个题目,包括300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组。

1、300.最长递增子序列

1.1 思路

1、为什么dp[i]是表示数组以nums[i]结尾的最长递增子序列的长度是dp[i]?

根据这种定义,状态转移方程也更容易理解。通常,dp[i] 可以根据 dp[j],其中 0 <= j < inums[j] < nums[i] 来更新。这表示我们可以考虑是否将 nums[i] 添加到以 nums[j] 结尾的最长递增子序列中,以获得更长的递增子序列。

2、为什么需要双重遍历?外层遍历和内层遍历分别表示什么意思?

外层遍历: 外层遍历的目的是确定最长递增子序列中的一个元素,通常表示当前考虑的子序列的结束位置。外层循环逐步移动,每一步都考虑下一个元素是否可以包括在最长递增子序列中。

内层遍历: 内层遍历的目的是与之前的元素进行比较,以确定是否可以将当前元素添加到最长递增子序列中。内层循环通常用于更新动态规划状态,以便计算以当前元素结尾的最长递增子序列长度。

  • dp数组以及下标的含义: dp[i]表示数组以nums[i]结尾的最长递增子序列的长度是dp[i]
  • 递推公式: dp[i] = Math.max(dp[i], dp[j] + 1);
  • dp数组如何初始化: Array.fill(dp, 1);
  • dp数组遍历顺序: 双层遍历,从小到大
  • 打印dp数组

1.2 代码

    public int lengthOfLIS(int[] nums) {
        int len = nums.length;
        int[] dp = new int[len];
        Arrays.fill(dp, 1);
​
        int res = 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[i], dp[j] + 1);
                }
​
                res = Math.max(res, dp[i]);
            }
        }
        return res;
    }

2、674. 最长连续递增序列

2.1 思路

1、为什么只需要一次遍历?

从数组的第二个元素开始进行遍历。对于每个元素nums[i],检查它是否大于前一个元素nums[i-1]。如果是,dp[i] = dp[i-1] + 1,表示当前元素可以加入前一个递增子序列中,增加子序列的长度;否则,dp[i] = 1,表示重新开始一个新的连续递增子序列

  • dp数组以及下标的含义: dp[i]表示数组以nums[i]结尾的连续最长递增子序列的长度是dp[i]
  • 递推公式: dp[i] = dp[i-1] + 1;
  • dp数组如何初始化: Array.fill(dp, 1);
  • dp数组遍历顺序: 一次遍历,从小到大
  • 打印dp数组

2.2 代码

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

3、718. 最长重复子数组

3.1 思路

1、子数组和子序列的区别?

子数组是原数组中的一段连续元素,而子序列是原序列中的一些元素,它们不必连续出现。

2、递推公式的理解?如何推导出 dp[i][j] = Math.max(dp[i][j], dp[i-1][j-1] + 1)

  • 如果 A[i] == B[j],那么我们可以在以 A[i-1]B[j-1] 为结尾的最长重复子数组后面加上一个相同的元素 A[i],从而使得最长重复子数组的长度加一,即 dp[i][j] = dp[i-1][j-1] + 1
  • 如果 A[i] != B[j],说明当前元素不相同,那么以 A[i]B[j] 为结尾的最长重复子数组的长度就是0,即 dp[i][j] = 0
  • dp数组以及下标的含义: dp[i][j]表示数组以nums1[i], nums2[j]结尾长度最长的公共子数组的长度是dp[i][j]
  • 递推公式: dp[i][j] = Math.max(dp[i][j], dp[i-1][j-1] + 1)
  • dp数组如何初始化
  • dp数组遍历顺序: 双层遍历,从小到大
  • 打印dp数组

3.2 代码

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

参考资料

代码随想录-300.最长递增子序列

代码随想录-674. 最长连续递增序列

代码随想录-718. 最长重复子数组