300_最长上升子序列


"""
给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例
输入: [10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。

进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
"""


# 方法一 动态规划
# 时间复杂度要求达到 o(nlogn)?? 意味着什么?。。意味着可能需采用二分查找
def lengthOfLIS1(nums):
    n = len(nums)
    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 or [0])




# 方法二 二分法
def lengthOfLIS2(nums):
    tails, res = [0]*len(nums), 0
    for num in nums:
        i, j = 0, res
        while i < j:
            m = (i+j) //2
            if tails[m] < m:
                i = m+1
            else:
                j = m
        tails[i] = num
        if j == res:
            res += 1
    return res


def lengthOfLIS3(nums):
    #时间复杂度为O(n * log(n))
    # if not nums: return 0
    tails = [float('-inf')] * len(nums)
    res = 0
    for num in nums:
        if num > tails[res - 1]:
            tails[res] = num
            res += 1
            continue
        left, right = 0, res - 1
        while left < right:
            mid = (left + right) // 2
            if num <= tails[mid]:
                right = mid
            else:
                left = mid + 1
        tails[right] = num
    return res




class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        # 堆数 piles = len(top)  
        top = []  # 堆顶元素数组

        for poker in nums:  # poker 当前牌
            # find left bound
            # 其实质是right往left方向靠
            left = 0
            right = len(top)
            while left < right:
                mid = (left + right) // 2
                if top[mid] == poker:
                    right = mid
                elif top[mid] < poker:
                    left = mid + 1
                elif top[mid] > poker:
                    right = mid

            # "left" is the left bound
            if left == len(top):
                top.append(poker)
            else:
                top[left] = poker

        return len(top)
        

nums = [10, 9, 2, 5, 3, 7, 101, 18]
print(lengthOfLIS1(nums))




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值