动态规划问题子序列问题02:最长连续增长子序列

116 阅读2分钟

最长连续增长子序列

力扣674. 最长连续递增序列 - 力扣(LeetCode)
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。
示例 1: 输入:nums = [1,3,5,4,7]
输出:3
解释:最长连续递增序列是 [1,3,5], 长度为3。尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。
示例 2:
输入: nums = [2,2,2,2,2]
输出: 1
解释: 最长连续递增序列是 [2], 长度为1。
本题相对于上一篇文章动态规划:300.最⻓递增⼦序列最⼤的区别在于“连续”。本题要求的是最⻓连续递增序列

动规五部曲:

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

dp[i]:以下标i为结尾的数组的连续递增的⼦序列⻓度为dp[i]。
注意这⾥的定义,⼀定是以下标i为结尾,并不是说⼀定以下标0为起始位置。

2. 确定递推公式

如果 nums[i] > nums[i - 1],那么以 i 为结尾的数组的连续递增的⼦序列⻓度 ⼀定等于 以i - 1为结尾的数组的连续递增的⼦序列⻓度 + 1 。
即:dp[i] = dp[i - 1] + 1;
注意这⾥就体现出和动态规划:最⻓递增⼦序列的区别!
因为本题要求连续递增⼦序列,所以就必要⽐较nums[i]与nums[i - 1],⽽不⽤去⽐较nums[j]与nums[i] (j是在0到i之间遍历)。既然不⽤j了,那么也不⽤两层for循环,本题⼀层for循环就⾏,⽐较nums[i] 和 nums[i - 1]。
这⾥⼤家要好好体会⼀下!

3. dp数组如何初始化

以下标i为结尾的数组的连续递增的⼦序列⻓度最少也应该是1,即就是nums[i]这⼀个元素。所以dp[i]应该初始1;

4. 确定遍历顺序

从递推公式上可以看出, dp[i + 1]依赖dp[i],所以⼀定是从前向后遍历。
本⽂在确定递推公式的时候也说明了为什么本题只需要⼀层for循环,代码如下:

        for(int i = 1; i < l; i++){
            dp[i] = 1;//初始化数组
            if(nums[i] > nums[i - 1])
                dp[i] = dp[i - 1] + 1;
            max = Math.max(max, dp[i]);//取最大连续递增序列
        }

5. 举例推导dp数组

image.png
分析完毕Java代码如下:

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