0300:最长递增子序列(★)
目录
题目
给你一个整数数组 nums
,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7]
是数组 [0,3,1,6,2,2,7]
的子序列。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18] 输出:4 解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3] 输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7] 输出:1
提示:
1 <= nums.length <= 2500
-104 <= nums[i] <= 104
进阶:
- 你能将算法的时间复杂度降低到
O(n log(n))
吗?
相似问题:
- 0334:递增的三元子序列
- 0354:俄罗斯套娃信封问题
- 0646:最长数对链
- 0673:最长递增子序列的个数
- 0712:两个字符串的最小ASCII删除和
- 1671:得到山形数组的最少删除次数(1912 分)
- 1964:找出到每个位置为止最长的有效障碍赛跑路线(1933 分)
- 2111:使数组 K 递增的最少操作次数(1940 分)
- 2370:最长理想子序列(1834 分)
- 2355:你能拿走的最大图书数量
- 2407:最长递增子序列 II(2280 分)
- 3177:求出最长好子序列 II(2364 分)
- 3176:求出最长好子序列 I(1849 分)
- 3201:找出有效子序列的最大长度 I(1663 分)
- 3202:找出有效子序列的最大长度 II(1973 分)
分析
#1 dp
按前一元素选哪个即可递推。
|
|
1000 ms
#2 dp+树状数组
- 观察递推式,限制了一个维度 (nums[j]<nums[i]),求另一个维度(f[j])最值
- 这种问题的一种常用方法是树状数组/线段树
- 将一个维度看作区间范围,维护区间内的最值即可
- 由于nums 元素可能为负,所以要归一处理后才能用树状数组
|
|
101 ms
#3 dp+有序集合
- 这种问题的另一种常用的方法是维护一种单调性
- 假如 num[j1]<=nums[j2] 且 f[j1]>=f[j2],显然 j2 对之后的递推式来说是无用的,可以去掉
- 那么维护有用的 <x=nums[j],y=f[j]> 的有序集合,x 和 y 都是递增的
- 遍历到 nums[i] 时,在这个有序集合中二分查找最后一个满足 x<nums[i] 的元素 <x,y>,即得到 f[i]=1+y
- 然后将所有不符合单调性的元素 <x,y> 去掉即可,类似单调栈
|
|
92 ms
#4 dp+单调数组
- f 的范围更方便处理,还可以考虑反过来,维护 <x=f[j],y=nums[j]> 的有序集合
- 遍历到 nums[i] 时,二分查找最后一个满足 y<nums[i] 的元素 <x,y>,得到 f[i]=1+x
- 然后将所有不符合单调性的元素 <x,y> 去掉
- 显然,这样的 k 最多一个,满足 x=f[i],y>=nums[i]
- 因此 f 可以直接用数组维护,将 f[i] 位置改为 nums[i] 即可
解答
|
|
37 ms