📜  资质 |门 CS 1998 |第 55 题(1)

📅  最后修改于: 2023-12-03 14:57:47.549000             🧑  作者: Mango

资质 | 门 CS 1998 | 第 55 题

简介:

本题是一道经典的算法题,要求求解给定数列中最长的上升子序列的长度。可以使用多种算法实现,如动态规划算法、贪心算法等,在面试或算法竞赛中常常被提及。

题意:

给定一个长度为n的数列a1,a2,……,an,找到其中最长的上升子序列的长度。

例如,对于数列[10,9,2,5,3,4],最长的上升子序列为[2,5]或[2,3,4],长度为3。

算法思路:

本题可以使用动态规划算法实现,具体步骤如下:

  1. 定义状态:dp[i]表示以数列的第i个元素结尾的最长上升子序列的长度。

  2. 初始化状态:对于每个dp[i],均初始化为1,因为每个元素本身都可以构成上升子序列。

  3. 状态转移:对于第i个元素,枚举它之前的所有元素j(0<=j<i),如果dp[j]+1>dp[i](j处的最长子序列长度加1比i处的最长子序列长度还要大),则更新dp[i]为dp[j]+1。

  4. 最终答案:经过以上三个步骤,最长上升子序列的长度即为dp数组中的最大值。

代码实现:
def lengthOfLIS(nums):
    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)

以上为Python代码实现,时间复杂度为O(n^2)。

优化思路:

上述算法的时间复杂度较高,可以使用二分查找优化算法,具体步骤如下:

  1. 定义一个tails数组,每次遍历时,如果当前数字大于tails数组的最大值,直接将其拼接至tails数组末尾。

  2. 如果当前数字小于tails数组的最大值,使用二分查找在tails数组中找到最小的比该数字大的位置,并将该位置的值替换为当前数字。

  3. 最终tails数组的长度即为所求的最长上升子序列的长度。

代码实现:
def lengthOfLIS(nums):
    n = len(nums)
    tails = [0] * n
    res = 0
    for num in nums:
        i, j = 0, res
        while i < j:
            mid = (i + j) // 2
            if tails[mid] < num:
                i = mid + 1
            else:
                j = mid
        tails[i] = num
        res = max(res, i + 1)
    return res

以上为Python代码实现,时间复杂度为O(nlogn)。