674. 最长连续递增序列 (longest continuous increasing subsequence)

3,908 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情

674. 最长连续递增序列 题目描述:给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。连续递增的子序列 可以由两个下标 l 和 rl < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。

示例1示例2
输入nums = [1,3,5,4,7]
输出33
解释:最长连续递增序列是 [1,3,5], 长度为 33。尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5577 在原数组里被 44 隔开。
输入nums = [2,2,2,2,2]
输出11
解释:最长连续递增序列是 [2], 长度为 11

中规中矩的动态规划

我们在 # 53. 最大子数组和 题解中探寻过连续子序列(子数组)问题的最优子结构。

1、确定 dp 状态数组

定义 dp[i]dp[i] 是以 num[i]num[i] 结尾的连续递增子序列的长度,其中 i[0,n),n=nums.lengthi \in [0,n),n=nums.length

2、确定 dp 状态方程

nums[i]>nums[i1]nums[i] > nums[i - 1] 时,以 num[i]num[i] 结尾的连续递增子序列的长度一定比以 num[i1]num[i - 1] 结尾的连续递增子序列的长度多 11,即 dp[i]=dp[i1]+1dp[i] = dp[i - 1] + 1

nums[i]nums[i1]nums[i] \le nums[i - 1] 时,dp[i]dp[i] 应重新计数,即 dp[i]=1dp[i] = 1

3、确定 dp 初始状态

dpdp 状态数组中元素初始化均为 00dp[0]dp[0] 是以 num[0]num[0] 结尾的连续递增子序列的长度。当只有一个元素时,最长连续递增序列的长度一定为 11,即 dp[0]=1dp[0] = 1

NOTE: dpdp 状态数组中元素初始化也可以均为 11。这样,当 nums[i]nums[i1]nums[i] \le nums[i - 1] 时,无须再给 dp[i]dp[i] 赋值为 11

4、确定遍历顺序

i=1i = 1i=n1i = n - 1

5、确定最终返回值

dp[n1]dp[n - 1] 只是以 num[i1]num[i - 1] 结尾的连续递增子序列的长度,不能代表全局最长连续子序列,故需要全局对比,即,max(...dp)max(...dp)

NOTE: ...dp...dp 代表将数组中所有元素按照其索引按顺序传到 maxmax 函数。

6、代码示例

/**
 * 空间复杂度 O(n),n是nums数组的长度
 * 时间复杂度 O(n)
 */
function findLengthOfLCIS(nums: number[]): number {
    const n = nums.length;
    const dp = new Array(n).fill(0);
    
    dp[0] = 1;
    
    for(let i = 1; i < n; i++) {
        if (nums[i] > nums[i - 1]) {
            dp[i] = dp[i - 1] + 1;
        } else {
            dp[i] = 1;
        }
    }
    
    return Math.max(...dp);
};
/**
 * 空间复杂度 O(n),n是nums数组的长度
 * 时间复杂度 O(n)
 */
function findLengthOfLCIS(nums: number[]): number {
    const n = nums.length;
    const dp = new Array(n).fill(1);
    
    for(let i = 1; i < n; i++) {
        if (nums[i] > nums[i - 1]) {
            dp[i] = dp[i - 1] + 1;
        }
    }
    
    return Math.max(...dp);
};

状态压缩:由于 dp[i]dp[i] 仅仅与 dp[i1]dp[i - 1] 相关,我们进行空间压缩。

/**
 * 空间复杂度 O(1)
 * 时间复杂度 O(n),n是nums数组的长度
 */
function findLengthOfLCIS(nums: number[]): number {
    const n = nums.length;
    let ans = 1;
    let dp = 1;
    
    for(let i = 1; i < n; i++) {
        if (nums[i] > nums[i - 1]) {
            dp += 1
        } else {
            dp = 1;
        }
        
        ans = Math.max(ans, dp)
    }
    
    return ans;
};

参考

# 重识动态规划