Top 100 Linked Question 修炼------第300题

本文探讨了如何求解最长升序子序列的长度问题,提供了两种算法实现:基于动态规划的时间复杂度为O(n^2)的方法和优化后的二分查找时间复杂度为O(nlogn)的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

300. Longest Increasing Subsequence

题目链接

题目解释:给出一个没有排序的整型数组,找到最长的升序序列的长度。

Example:

Input: 
[10,9,2,5,3,7,101,18]
Output: 4 
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. 

注意

  • 可能会存在多个相同长度的最长升序序列,你只是需要返回他们的长度即可。
  • 算法的时间复杂度必须为O(n^2)

Follow up:尝试优化你的算法,使其时间复杂度为O(n\log n)

题目分析:首先,在分析题目的时候,我们不是求解最长升序子序列,而是序列,即不要求数字相邻。既然出现了最长这个字眼,我们可以尝试往动态规划这个方向去想。

设计一个数组dp,其中容易得到状态转移方程为dp[i]=max(dp[i],dp[j]+1),其中dp[i]的值为nums[:i]中升序数组的长度。

那么这样就是比较容易的写出了整个的解题代码:

    def lengthOfLIS(self, nums):
        """
        基于简单DP:时间复杂度为O(n^2),空间复杂度为O(n),这个也是计算最长升序序列的方法
        :type nums: List[int]
        :rtype: int
        """
        # 初始化dp数组
        dp=[1]*len(nums)
        for i in range(len(nums)):
            for j in range(i):
                # 从0-i中看比nums[i]小的元素,一轮更新完成后dp[i]的值为nums[:i]中升序数组的长度
                if nums[j] < nums[i]:
                    dp[i] = max(dp[i], dp[j] + 1)
        return max(dp) if dp else 0

那么可以继续进行思考,怎么把算法进行优化,使其时间复杂度为O(n\log n)呢?

可能一眼看过去是没有任何思路的。然后,我们去分析时间复杂度,既然时间复杂度是要求O(n\log n),出现了logn这个选项,那么可不可以尝试使用二分查找呢?因为外面还乘了一个n,一般情况下是一次遍历。

但是又出现了一个问题,就是我们在使用二分查找的时候,要求数组是已经排完序的,而我们的数组是没有排序的。

使用一个二分查找的方式,找到递增子数组中大于等于当前值的第一个数的位置;
如果找到,则利用当前值替换;否则将当前值加入到递增子数组中,表明该值比子数组的值都大,可能输入子数组。
例子:nums = [5,6,7,1,2,8,3,4,0,5,9]:
遍历到 7: res = [5,6,7];
遍历到 2: res = [1,2,7];
遍历到 8: res = [1,2,7,8];
遍历到 3: res = [1,2,3,8];
遍历到 4: res = [1,2,3,4];
剩下三个元素 : res = [0,2,3,4,5,9];
最后我们就可以得到最长递增子序列的长度,但是这里要注意得到的子序列不是真正的子序列,然而其长度是正确的。
该算法无法得到最长递增子序列,仅计算长度。

    def lengthOfLIS(self, nums):
        """
        二分查找,时间复杂度O(nlogn),空间复杂度O(n)
        """
        tails = [0] * len(nums)
        size = 0
        for x in nums:
            i, j = 0, size
            while i != j:
                m = (i + j) / 2
                if tails[m] < x:
                    i = m + 1
                else:
                    j = m
            tails[i] = x
            size = max(i + 1, size)
        return size

Reference

https://blog.csdn.net/Koala_Tree/article/details/80062211

总结

2019/6/10:Good Good study,day day up.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值