题目链接
最长上升子序列
题目描述
注意
- 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序
- 尽量节省时间
解答思路
- 遍历整个数组,从左到右动态规划计算以每个元素为尾部元素的最长上升子序列:储存每个元素的最长上升子序列,当访问到某个元素时,从左往右遍历其前方的所有元素,找到比当前元素小的尾部值中最长上升子序列的最大值,在最大值的基础上加1就是以当前元素为尾部值的最长上升子序列
- 在动态规划的基础上,采用二分查找寻找在当前元素之前的元素的最长上升子序列的最大值。方法是用一个tails数组存储上升序列长度为i的最小尾部值,其实际长度为当前的最长上升子序列,则该tails数组是单调递增的。遍历到每个元素时,判断如果此时tails数组中的最长上升序列的尾部元素的值都小于此时的元素值,则更新最长上升序列,并更新tails数组中的实际长度以及该长度处的最小尾部值为当前元素值;否则在tails实际数组范围中查找出第一个比当前元素值大的位置,并更新其值为当前元素值
代码
class Solution {
public int lengthOfLIS(int[] nums) {
int[] tails = new int[nums.length];
tails[0] = nums[0];
int res = 1;
for(int num : nums) {
int i = 0;
int j = res;
if(tails[res - 1] < num) {
tails[res] = num;
res++;
continue;
}
while(i < j) {
int m = (i + j) / 2;
if(tails[m] < num) {
i = m + 1;
}
else {
j = m;
}
}
tails[i] = num;
}
return res;
}
}
关键点
- 通过tails数组存储存储上升序列长度为i的最小尾部元素的值
- tails数组是单调递增的
- 当tails数组实际范围中存在比当前元素值大的尾部值,则需要找到满足该条件的第一个值在tails数组中的位置,并更新该位置的值为当前元素值,以保证该位置处的tails值是最小尾部值
|