import java.util.*;
public class Solution {
/**
* retrun the longest increasing subsequence
* @param arr int整型一维数组 the array
* @return int整型一维数组
*/
//思路:
/*
1.维护一个临时数组tmp,这里面存储当前的最长上升子序列;
2.遍历arr中的元素,不断的将当前元素加入tmp,或者替换tmp中的元素,使得tmp保持上升;
2.1 对于arr[i] ,若其大于tmp的最后一个元素,那么直接将其加入到tmp的末尾,
2.2 对于arr[i],若其小于tmp的最后一个元素,则在tmp从左到右中找到第一个比奇大的元素并替换他
3.每次处理完一个arr[i],都将arr[i]加入到或者替换到tmp的位置记录到pos中,如pos[i]表示arr[i]在tmp中的位置
4.整过程中,tmp的长度都是不减的,因此,最后tmp的长度就是最长上上升子序列的长度,从tmp的最后一个元素开始向前遍历(s从后往前是为了
保证,结果是按字典序取最小的要求,这一点你们自己思考吧,不难),在pos中寻找位置为tmp中对应位置的pos[i],将arr[i]记录到结果数组中即可。
*/
public int[] LIS (int[] arr) {
if(arr == null || arr.length == 0) return arr ;
//tmp[i]表示 当前最长上升子序列 i位置的 元素
int tmp[] = new int[arr.length] ;
//pos[i]表示 将arr[i]加入当前最长上升子序列中 时arr[i]应该在序列中的 位置
int pos[] = new int[arr.length] ;
tmp[0] = arr[0] ;
pos[0] = 0 ;
int tmpIndex = 0 ;//当前最长上升子序列的最后一元素的 位置
for(int i = 1 ; i < arr.length ; i ++) {
if(arr[i] > tmp[tmpIndex]) {
tmp[++ tmpIndex] = arr[i] ;
pos[i] = tmpIndex ;
} else if(arr[i] == tmp[tmpIndex]) {
pos[i] = tmpIndex ;
} else {
//二分查找位置
int findIdx = findPos(tmp , tmpIndex , arr[i]) ;
tmp[findIdx] = arr[i] ;
pos[i] = findIdx ;
}
}
int res[] = new int[tmpIndex + 1] ;
for(int j = tmpIndex , i = arr.length - 1 ; j >= 0 ; i --) {
if(pos[i] == j) {
res[j --] = arr[i] ;
}
}
return res ;
}
//在tmp中 查找第一个比target大的数
public int findPos(int tmp[] , int end , int target) {
int i = 0 ;
int j = end ;
while(i <= j) {
int mid = i + (j - i) / 2 ;
if(target > tmp[mid]) {
i = mid + 1 ;
} else {
j = mid - 1 ;
}
}
return i ;
}
}