📜  数组的边界元素可能导致的最长递增序列(1)

📅  最后修改于: 2023-12-03 15:10:22.842000             🧑  作者: Mango

数组的边界元素可能导致的最长递增序列

当处理数组时,我们经常需要考虑边界情况,特别是数组的边界元素可能对最终结果产生影响的情况。一个经典的问题就是求解最长递增子序列(LIS),而数组的边界元素可能对 LIS 问题的解法产生影响。

问题描述

给定一个整数数组 nums,找到其中最长严格递增子序列的长度。

一个严格递增子序列是指在原数组中选出一个子序列,使得所有子序列中相邻元素的差都比前一个子序列里的相邻元素的差小。

例如,对于数组 [0, 8, 4, 12, 2],最长递增子序列为 [0, 4, 12],长度为 3。

解决方案

求解 LIS 问题可以采用动态规划的方法。定义 dp[i] 表示以 nums[i] 结尾的最长递增子序列的长度。显然,当 i=0 时,dp[0] 为 1。

对于 i>0,我们需要枚举所有 j < i 的情况来更新 dp[i]。具体而言,对于任何 j<i,如果 nums[j] < nums[i],则 dp[i] = max(dp[i], dp[j] + 1)。完成所有更新后,我们可以得到 dp 数组中的最大值,就是所求的最长递增子序列的长度。

def lengthOfLIS(nums: List[int]) -> int:
    n = len(nums)
    if n == 0:
        return 0

    dp = [1] * n
    for i in range(1, n):
        for j in range(i):
            if nums[j] < nums[i]:
                dp[i] = max(dp[i], dp[j] + 1)

    return max(dp)

这段代码可以得到正确的答案,但是还存在一些问题。当 nums 中只有一个元素,或者所有元素都相同的时候,上述代码会输出错误的结果。

例如,对于数组 [1],我们期望输出 1,但是上述代码会输出 0。

为什么会出现这种情况呢?观察一下动态规划的状态转移方程,我们可以发现当 j<inums[j] < nums[i] 的时候,dp[i] 只能从 dp[j] 转移过来。这意味着如果 nums[i] 不大于数组中的任意一个元素,它无法被计入任何最长递增子序列的候选者中。

因此,为了避免上述问题,我们需要在动态规划过程中初始化 dp 数组。具体而言,当 i=0 的时候,dp[0] 应该置为 1,否则 dp[0] 可能会被错误地更新。

def lengthOfLIS(nums: List[int]) -> int:
    n = len(nums)
    if n == 0:
        return 0

    dp = [1] * n
    for i in range(n):
        for j in range(i):
            if nums[j] < nums[i]:
                dp[i] = max(dp[i], dp[j] + 1)

    return max(dp)

现在,我们得到了一个正确的动态规划解法。该算法的时间复杂度为 $O(n^2)$,可以通过本题的测试数据。