您的位置:首页 > 产品设计 > UI/UE

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

2020-01-14 18:13 459 查看

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

  • 动态规划+二分查找
  • 题解

    动态规划

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

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

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

    3. 遍历dpdpdp,对于iii,遍历区间[1,n)[1,n)[1,n):

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

    复杂度分析

    • 时间复杂度:O(n2)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(待完成)

    动态规划+二分查找

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

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

    复杂度分析

    • 时间复杂度:O(nlog(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(待完成)

    • 点赞
    • 收藏
    • 分享
    • 文章举报
    朱师傅哈 发布了84 篇原创文章 · 获赞 1 · 访问量 755 私信 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: 
    相关文章推荐