给定数组arr,设长度为n,输出arr的最长递增子序列。

给定数组arr,设长度为n,输出arr的最长递增子序列。(如果有多个答案,请输出其中字典序最小的)
示例1

[2,1,5,3,6,4,8,9,7]

输出

[1,3,4,8,9]

示例2:
输入

[1,2,8,6,4]

返回值

[1,2,4] 其最长递增子序列有3个,(1,2,8)、(1,2,6)、(1,2,4)其中第三个字典序最小,故答案为(1,2,4)

参考:此处为参考地址

一共需要两个辅助数组和一个辅助变量:
dp数组:用来存储位置i对应的最长子序列的长度
end数组:用来存储长度为i的子序列的最后一个元素的最小值
len:用来记录当前找到的最长子序列的长度
 
举个例子
[3,2,5,8,6,7]
end数组:
i=0: 3 长度为1的子序列为:3
        end=[3]
i=1:2<3 长度为1的子序列为:2(2替换3,因为这是是最容易使子序列扩展为长度为2的子序列的值)
         end=[2]
i=2:5>2  所以长度为1的子序列可以扩展成一个长度为2的子序列
        长度为1的子序列为:2
        长度为2的子序列为:2 5
        end=[2 5]
i=3:8>5 所以长度为2的子序列可以扩展成一个长度为3的子序列
        长度为1的子序列为:2
        长度为2的子序列为:2 5
        长度为3的子序列为:2 5 8
        end=[2 5 8]
i=4:6>5&&6<8 所以长度为2的子序列可以扩展成一个长度为3的子序列
        长度为1的子序列为:2
        长度为2的子序列为:2 5
        长度为3的子序列为:2 5 6(6替换8,因为只是最容易使子序列扩展为长度为4的子序列的值)
        end=[2 5 6]
i=5:7>6 所以长度为3的子序列可以扩展成一个长度为4的子序列
        长度为1的子序列为:2
        长度为2的子序列为:2 5
        长度为3的子序列为:2 5 6
        长度为4的子序列为:2 5 6 7   
        end=[2 5 6 7]
笔记:我们用end[i]来存储长度为i+1的子序列的最后一个元素的最小值,因为这是最有希望使子序列扩展的值
当a[x]>end[i]时,那么长度为i+1的子序列必定可以扩展成一个i+2的子序列,如果(old=end[i+1])>a[x],那么就令
end[i+1]=a[x],他的含义是只要a[y]>a[x]即使a[y]<old,那么长度为i+2的子序列也必然可以扩展为一个长度为i+3的子序列。
所有最终结束时end数组为[2,5,6,7]即end[i]表示长度为(i+1)的子序列的最后一个元素值。
 
 
遍历结束后也会生成    dp数组:
arr:[3,2,5,8,6,7]
dp :[1 1 2 3 3 4]
len=4
dp[i]表示到arr[i]为止最长的递增子序列,得到字典序最小的元素只需要倒过来遍历dp,依次输出最先遇到的长度为len,len-1,len-2....1的arr元素即可。
res用来存储字典序最小的最长子序列。
即:    len=4  dp[5]==4 ==>res[3]=arr[5]=7
    len=3  dp[4]==3 ==>res[3]=arr[4]=6
         dp[3]==3  pass因为需要的是字典序最小的
        len=2  dp[2]==2 ==>res[3]=arr[2]=5
    len=1  dp[1]==1 ==>res[3]=arr[1]=2
         dp[0]==1  pass因为需要的是字典序最小的
    结果:res=[2,5,6,7]
笔记:设dp[x]==dp[y]&&x<y那么a[x]必定大于a[y],因为如果a[x]<a[y],那么dp[x]对应的子序列必定可以扩展为长度dp[x]+1的子序列即dp[y]=dp[x]+1>dp[x],矛盾,所以a[y]<a[x]
class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        dp = [1 for _ in range(len(nums))]
        len_lis = 1
        for i in range(1, len(nums)):
            for j in range(0, i):
                if nums[j] < nums[i]:
                    dp[i] = max(dp[j] + 1, dp[i])
                    if dp[i] > len_lis:
                        len_lis = dp[i]
        res = [0 for _ in range(len_lis)]
        #print(dp)
        for i in range(len(dp)-1, -1, -1):
            if dp[i] == len_lis:
                #print(len_lis)
                res[len_lis-1] = nums[i]
                len_lis -= 1
        return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值