📜  最长递增子序列数(1)

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

最长递增子序列数

介绍

在计算机算法中,最长递增子序列数(Longest Increasing Subsequence,LIS)是指一个序列中最长的严格递增子序列的长度。这个子序列不需要在原序列中是连续的。

求解最长递增子序列数这个问题是一个经典的动态规划问题,也有其他算法,如 Patience sorting 等。

动态规划算法

动态规划算法是LIS问题的常见解决方案,时间复杂度为O(n^2)。

动态规划的思路如下:

  • 定义状态:$dp[i]$ 表示以 $nums[i]$ 结尾的最长递增子序列的长度。
  • 初始化状态:初始化所有 $dp[i]$ 为1,因为每个数最长递增子序列的长度至少是1。
  • 状态转移:对于 $0 \le j < i$,如果 $nums[i] > nums[j]$,则 $dp[i] = max(dp[i], dp[j]+1)$。
  • 找出最长递增子序列:在计算最长递增子序列的长度时,需要找到所有的 $dp[i]$ 中的最大值。

下面是使用Python实现的动态规划算法:

def lengthOfLIS(nums: List[int]) -> int:
    n = len(nums)
    dp = [1] * n
    for i in range(n):
        for j in range(i):
            if nums[i] > nums[j]:
                dp[i] = max(dp[i], dp[j]+1)
    return max(dp)
Patience排序算法

Patience排序算法是一种求解最长递增子序列数的优秀解决方案,时间复杂度为O(n log n)。

Patience排序算法的思路如下:

  • 定义状态:定义一个栈数组 $stack$,每个元素表示一个堆,堆顶为最大值。同时定义一个 $tail$ 数组,$tail[k]$ 表示长度为 $k$ 的递增子序列的结尾最小值。
  • 状态转移:遍历 $nums$ 数组,对于每个数 $x$,如果 $x$ 大于 $tail$ 中所有值,说明 $x$ 可以接在 $tail$ 数组中最长的递增子序列后面形成一个更长的递增子序列;否则将 $x$ 加入到 $tail$ 中最靠近 $x$ 的比 $x$ 小的元素的堆后面。
  • 找出最长递增子序列:最长递增子序列的长度就是 $tail$ 数组最后一个非空元素的下标加1。

下面是使用Python实现的Patience排序算法:

from bisect import bisect_left

def lengthOfLIS(nums: List[int]) -> int:
    piles = []
    for num in nums:
        pile = bisect_left(piles, num)
        if pile == len(piles):
            piles.append(num)
        else:
            piles[pile] = num
    return len(piles)
总结

求解最长递增子序列数是一个经典的算法问题,在实际应用中也非常常见。动态规划算法和Patience排序算法分别是这个问题的两种主要解决方案,具有不同的时间复杂度和效率。在编写解决方案时,需要根据实际情况选择合适的算法。