给定数组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