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

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

在数组的排序表示中形成子数组的最长递增子序列

当我们需要在一个数组中找到最长的递增子序列时,可以使用动态规划的思想,用一个数组来记录最长递增子序列的长度。具体做法是对于每一个数,看它前面有多少个比它小的数,把这些数的最长递增子序列长度加上1就可以得到当前数的最长递增子序列长度。由于每次都要遍历之前的数,时间复杂度为O(n^2)。

但是,在数组的排序表示中形成子数组的最长递增子序列有一种更有效的解法,时间复杂度为O(nlogn)。具体来说,我们可以维护一个数组dp,表示长度为i的最长递增子序列的末尾最小的数。例如,dp[2]表示长度为2的最长递增子序列的末尾最小的数。初始时,dp[1] = nums[0]。之后,对于每个数nums[i],如果它比dp[j]大,那么它可以接在dp[j]的后面形成一个长度为j+1的递增子序列,更新dp[j+1]=nums[i]。否则,找到dp[k-1]<nums[i]<dp[k]的位置k,更新dp[k]=nums[i]。最后,dp数组中最后一个非零数的下标就是最长递增子序列的长度。

下面是代码实现:

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

以上代码中,i和j表示dp数组中的下标范围,初始时为0和最大长度res。在while循环中,每次找到dp数组中第一个大于等于num的数的位置,更新dp数组中该位置的值。最后返回dp数组中最后一个非零数的下标加1就是最长递增子序列的长度。

这个算法的时间复杂度为O(nlogn),因为每次找到第一个大于等于num的位置可以使用二分查找,时间复杂度为O(logn)。