LeetCode Medium 300 最长升序子序列 Python

75 篇文章 0 订阅
72 篇文章 0 订阅

方法一:   

算法:动规

    思路

            如果设立动规状态dp(i)为前i个元素组成的最长上升序列的长度的话,dp(i)和dp(i-1)建立不起来联系,

        因为这里的升上序列不要求是连续的,元素可以是跳着的

            设立动规状态dp(i)为以第i个元素为结尾的最长上升序列的长度,则dp(i)所代表的序列中,nums[i]是

        最大以nums[i]为结尾的最长上升序列中的最后一个元素

            显然,dp[i]初始化为1,亦即边界条件

            状态转移方程:

                dp(i)与dp(i-1)的关系是,如果nums[i] > nums[i-1],显然dp(i) = dp(i-1) + 1

                但是如果不大于nums[i-1]的话,就应该在nums[0:i]之间找nums[j]<nums[i]的最大的那个dp(j)+1

                的值,dp(i) = dp(j_the_max)+1

                故用一个for 从(0:i)遍历并判断与更新

    复杂度分析

        时间:ON2,两层for,且都和N相关

        空间:ON,dp列表的空间

def lengthOfLIS( nums):

    if not nums:

        return 0

    dp = [1] * len(nums)

    ans = 1

    for i in range(1, len(nums)):

        for j in range(i):

            if nums[i] > nums[j] and dp[i] < dp[j] + 1:

                dp[i] = dp[j] + 1

        ans = max(ans, dp[i])

    return ans


方法二:

    算法:二分查找

    思路

        维护一个数组stack,stack中记录的是,遍历到某个元素时,含当前元素的递增子序列

        用二分查找找到当前元素num的插入位置

 

            如果当前元素num比所有元素都大,即大于栈顶元素,那么push压栈

            否则说明在第i个位置处的元素stack[i]不大于num,用【二分查找】找到这个位置pos

            并另stack[pos] = nums[i]

            注意如过nums[i]和stack中的元素相等的话,比如stack = [1,2],nums[i] = 2

            二分查找得到的pos会等于2,超出数组长度,然而当元素相等的时候,其实是不用替换操作的,

            所以要用 stack[pos-1] != nums[i]来做限定

        最后len(stack)就是保存的最长递增序列的长度

        (因为递增子序列是有序的,所以这里用二分)

    复杂度分析

        时间:NlogN,外面for循环ON,内部二分查找logN

        空间:OK,K为最长子序列长度

def lengthOfLIS1( nums):

    import bisect

    if not nums:

        return 0

    stack = [nums[0]]

    for i in range(1, len(nums)):

        if nums[i] > stack[-1]:

            stack.append(nums[i])

        else:

            pos = bisect.bisect(stack, nums[i])

            if stack[pos - 1] != nums[i]:

                stack[pos] = nums[i]

    return len(stack)

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值