From
Leetcode
Status
回头复习下
Date
Apr 23, 2024
Tags
动态规划
子序列问题
Difficulty
中等
题面
给你一个整数数组
nums
,找到其中最长严格递增子序列的长度。子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,
[3,6,2,7]
是数组 [0,3,1,6,2,2,7]
的子序列
。
示例 1:
示例 2:
示例 3:
提示:
1 <= nums.length <= 2500
104 <= nums[i] <= 104
进阶:
- 你能将算法的时间复杂度降低到
O(n log(n))
吗?
思路
动态规划之子序列问题入门题
题解
动态规划
贪心+二分
比如序列是78912345,前三个遍历完以后tail是789,这时候遍历到1,就得把1放到合适的位置,于是在tail二分查找1的位置,变成了189(如果序列在此时结束,因为res不变,所以依旧输出3),再遍历到2成为129,然后是123直到12345
- tails数组的定义:tails数组是用来存储当前找到的最长递增子序列的尾部元素。在任意时刻,tails[k]的值代表长度为k+1的最长递增子序列的尾部元素的最小值。
- 变量res表示当前发现的最长递增子序列的长度。
- 循环遍历nums数组:
- 对于每个元素num,使用二分查找在tails数组中找到num应该插入的位置,即tails数组中第一个大于等于num的元素的位置。
- 二分查找的范围是[0, res),其中i是左边界,j是右边界。
- 二分查找过程:
- 计算中点m = (i + j) / 2。
- 如果tails[m] < num,则说明num应该在m之后的位置,因此更新左边界i = m + 1。
- 否则,num应该在m或之前的位置,因此更新右边界j = m。
- 更新tails数组:
- 找到的i即是num应该插入的位置。将tails[i]更新为num。
- 如果num的插入位置i等于当前递增子序列长度res,意味着num可以作为一个新的、更长的递增子序列的尾部,因此res自增1。
- 循环结束后,变量res即为最长递增子序列的长度。