300. 最长上升子序列(Longest Increasing Subsequence)

题解

动态规划

d p [ i ] dp[i] dp[i]表示到当前位置的最长上升子序列的长度。

  1. 特判,若数组为空,返回0

  2. 初试化 d p = [ 1 , 1 , ⋯   , 1 ] dp=[1,1,\cdots,1] dp=[1,1,,1],长度为 n n n d p [ i ] = 1 dp[i]=1 dp[i]=1表示每一位都可以为长度为1的最长上升子序列。

  3. 遍历 d p dp dp,对于 i i i,遍历区间 [ 1 , n ) [1,n) [1,n)

    • 遍历当前位置前的所有位置 j j j,遍历区间 [ 0 , i ) [0,i) [0,i)
      • n u m s [ i ] > n u m s [ j ] nums[i]>nums[j] nums[i]>nums[j],表示满足上升的条件。此时,更新当前位置的最长上升子序列的长度: d p [ i ] = m a x ( d p [ i ] , d p [ j ] + 1 ) dp[i]=max(dp[i],dp[j]+1) dp[i]=max(dp[i],dp[j]+1)
  4. 返回 d p dp dp中的最大值。

复杂度分析

  • 时间复杂度: O ( n 2 ) O(n^{2}) O(n2)
  • 空间复杂度: O ( n ) O(n) O(n)

Python

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        if(not nums):
            return 0
        n=len(nums)
        dp=[1]*n
        for i in range(n):
            for j in range(i):
                if(nums[i]>nums[j]):
                    dp[i]=max(dp[i],dp[j]+1)
        return max(dp)

Java(待完成)

动态规划+二分查找

定义 t a i l tail tail数组, t a i l [ i ] tail[i] tail[i]保存遍历过程中长度为 i + 1 i+1 i+1的最长上升子序列的最小尾元素。
t a i l tail tail本身要求严格递增。
最终 t a i l tail tail的长度就是整个数组最长上升子序列的长度。
解释:
这里长度等于最长上升子序列的长度,但是 t a i l tail tail不一定为最长上升子序列。

  1. 特判,若数组长度小于 2 2 2,返回数组长度。
  2. 初始化 t a i l = [ n u m s [ 0 ] ] tail=[nums[0]] tail=[nums[0]],表示目前为止长度为1的最长上升子序列的最小尾元素为 n u m s [ 0 ] nums[0] nums[0]
  3. 遍历数组,对于 i i i,遍历区间 [ 1 , n ) [1,n) [1,n)
    • n u m s [ i ] > t a i l [ − 1 ] nums[i]>tail[-1] nums[i]>tail[1] t a i l [ − 1 ] tail[-1] tail[1]表示最后一个元素。若当前的数组元素比 t a i l tail tail的最后一个元素大,将其加入 t a i l tail tail。跳过后续步骤。
    • 若不满足,则在 t a i l tail tail中找到第一个比他大的元素,替换掉。使用二分查找,查找替换位置。
    • 定义左界 l = 0 l=0 l=0,右界 r = l e n ( t a i l ) − 1 r=len(tail)-1 r=len(tail)1
    • 进入循环,循环条件 l < = r l<=r l<=r
      • 定义 m i d = ( l + r ) / / 2 mid=(l+r)//2 mid=(l+r)//2
      • n u m s [ i ] < = t a i l [ m i d ] nums[i]<=tail[mid] nums[i]<=tail[mid],更新右界: r = m i d − 1 r=mid-1 r=mid1
      • 否则, l = m i d + 1 l=mid+1 l=mid+1
    • 替换, t a i l [ l ] = n u m s [ i ] tail[l]=nums[i] tail[l]=nums[i]
  4. 返回 t a i l tail tail的长度。

复杂度分析

  • 时间复杂度: O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))
  • 空间复杂度: O ( n ) O(n) O(n)

Python

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        if(not nums):
            return 0
        n=len(nums)
        if(n<2):
            return n
        tail=[nums[0]]
        for i in range(1,n):
            if(nums[i]>tail[-1]):
                tail.append(nums[i])
                continue
            l=0
            r=len(tail)-1
            while(l<=r):
                mid=(l+r)//2
                if(tail[mid]>=nums[i]):
                    r=mid-1
                else:
                    l=mid+1
            tail[l]=nums[i]
        return len(tail)

Java(待完成)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值