📜  最长递增的子序列,在数组的排序表示形式中形成子数组(1)

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

最长递增子序列

在一个数组中,最长递增子序列指的是一个子序列中,所有元素都是递增的,并且长度尽可能地长。

例如,在数组 [10, 9, 2, 5, 3, 7, 101, 18] 中,最长递增子序列是 [2, 3, 7, 101],长度为 4。

本文将介绍一些解决这个问题的算法。

解法一:动态规划

我们可以使用动态规划算法来解决这个问题。

首先,我们用一个一维数组 dp 来表示以每个元素为结尾的最长递增子序列的长度。初始值被全部初始化为 1,因为每个元素都可以单独构成一个子序列。

接着,我们枚举数组中的每个元素 i,然后再次枚举 j,其中 0 <= j < i。如果 nums[j] < nums[i],那么 nums[i] 可以接在 nums[j] 的后面形成一个更长的递增子序列。因此,我们可以得出转移方程:

dp[i] = max(dp[i], dp[j] + 1)

最终的答案是数组 dp 中的最大值。

代码如下:

def lengthOfLIS(nums):
    if not nums:
        return 0

    n = len(nums)
    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)

时间复杂度:O(n^2)

解法二:贪心算法 + 二分查找

我们还可以使用贪心算法和二分查找来解决这个问题。

我们维护一个数组 d,其中 d[i] 表示长度为 i 的最长递增子序列的结尾最小值,即长度为 i 的递增子序列的结尾要尽量小。

例如,在输入数组 [0, 8, 4, 12, 2] 中,当 i = 1 时,d[1] 的值应该是 8,因为长度为 1 的最长递增子序列为 [0] 或 [8],其中结尾最小的是 8。

接着,我们遍历输入数组,对于每个元素,我们在数组 d 中查找第一个比它大的元素,将其替换为当前元素。如果没有比它大的元素,我们就在数组 d 的末尾添加这个元素。

最终,数组 d 的长度就是最长递增子序列的长度。

代码如下:

def lengthOfLIS(nums):
    if not nums:
        return 0

    d = []
    for num in nums:
        if not d or num > d[-1]:
            d.append(num)
        else:
            left, right = 0, len(d) - 1
            while left < right:
                mid = (left + right) // 2
                if d[mid] < num:
                    left = mid + 1
                else:
                    right = mid
            d[left] = num

    return len(d)

时间复杂度:O(nlogn)

总结

本文介绍了两种解决最长递增子序列问题的算法:动态规划和贪心算法 + 二分查找。

动态规划算法的时间复杂度是 O(n^2),空间复杂度是 O(n)。

贪心算法 + 二分查找的时间复杂度是 O(nlogn),空间复杂度是 O(n)。

在实际应用中,通常会使用贪心算法 + 二分查找来解决这个问题,因为它更加高效。