给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。
输入格式
第一行包含整数N。
第二行包含N个整数,表示完整序列。
输出格式
输出一个整数,表示最大长度。
数据范围
1≤N≤1000001≤N≤100000,
−109≤数列中的数≤109−109≤数列中的数≤109
输入样例:
7
3 1 2 1 8 5 6
输出样例:
4
思想:
难点:假如我们得到了一个子序列,但是突然出现一个小于栈顶的数值,我们不确定这个数值加上之后的序列会不会超过我们已经得到的序列长度,因此我们就不会这道题;所以此刻就不能添加与删除,添加删除都会改变子序列的长度。所以我们只能更新。这样就维护了我们子序列的长度,来了大于栈顶的数直接添加更新栈长,遇到小于栈顶元素的直接二分查找到,它所修改的位置更新,你甚至可以更新整个栈,反正不会影响栈的长度。最终的结果就是栈长,这就是步步更新。
import java.io.*;
import java.lang.*;
class Main{
static int n = 0, N = 100010;
static int[] a = new int[N], st = new int[N];
static int hh = 0;
static int binserySearch(int num, int[] nn){//找到从右到左第一个大于num的数
int l = 1;
int r = hh;
while(l < r){
int mid = l + r >> 1;
if(nn[mid] >= num)r = mid;
else l = mid + 1;
}
return l;
}
public static void main(String[] args)throws Exception{
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
n = Integer.valueOf(buf.readLine());
String[] nums = buf.readLine().split(" ");
for(int i = 1; i <= n; ++i){
a[i] = Integer.valueOf(nums[i - 1]);
int index = binserySearch(a[i], st);//找到大于a[i]的下标
if(hh == 0 || st[hh] < a[i]){//栈空或者栈不存在这个数并且栈顶元素大于该数
st[++hh] = a[i];//更新长度
}else if(st[index] > a[i]){//更新序列最小值
st[index] = a[i];
}
}
System.out.print(hh);
}
}