题目描述
题目链接:最长上升子序列 _ 牛客网
给定数组 arr ,设长度为 n ,输出 arr 的最长上升子序列。(如果有多个答案,请输出其中 按数值(注:区别于按单个字符的ASCII码值)进行比较的 字典序最小的那个)
数据范围: 10000000000≤n≤200000,0≤ arri ≤1000000000 要求:空间复杂度 O(n),时间复杂度O(nlogn)
示例
输入: [2,1,5,3,6,4,8,9,7]
返回值: [1,3,4,8,9]
解题思想:动态规划
代码注释中 可能会遇到的疑问解释:
1,替换的主要作用就是,找到arr当前的元素,在temp中的位置,从而确定它的长度。 比如temp数组元素为[2,4,6] , 而arr中当前元素为5,那temp中第一个大于5的元素就是6,那5的长度就是3 。同时替换掉后,也能不影响后续元素位置的 判定。 2,因为当arr数组的当前元素 ,小于temp数组的最后一个元素时,只是替换temp中的元素,而不增加,因此不更新max值 。 3,要从后往前遍历,比如arr数组为[2,5,3,6,4] ,对应的元素长度 len数组为[1,2,2,3,3] ,根据题意得到的字典序最小的 最长子序列应该是[2,3,4] ,而通过从后往前遍历就可以实现,原理是,后面小的元素会替换前面大的元素,所以相同长度下,一定是后面的元素更小。
代码注释
import java.util.*;
public class Solution {
public int[] LIS (int[] arr) {
int n = arr.length;
int[] temp =new int[n];
int[] len = new int[n];
int max =0;
for(int i=0;i<n;i++){
?
?
?
?
if(i==0 || temp[max-1]<arr[i]){
?
temp[max++]=arr[i];
?
len[i]= max;
?
}else{
?
?
int index = search(temp,max,arr[i]);
temp[index]= arr[i];
?
len[i]=index +1;
}
}
?
int[] res = new int[max];
for(int i=n-1;i>=0;i--){
?
if(len[i] == max)
?
res[--max] = arr[i];
}
return res;
}
public int search(int[] temp,int max,int arrI){
int left = 0;
int right = max-1;
while(left<right){
int mid = left+(right-left)/2;
if(temp[mid]>= arrI){
right = mid;
}else{
left = mid+1;
}
}
return left;
}
}
|