题目描述:
求最大上升子序列,利用贪心+二分的思想,关键注释都在代码块中了。
学习来源链接:https://blog.csdn.net/lxt_Lucia/article/details/81206439,感谢大佬的博客
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
int L, dp[100005], s[100005], len, ll, rr, mm;
int main(){
while(scanf("%d",&L) != EOF){
for(int i = 1;i <= L;i++){
scanf("%d",&s[i]);
}
len = 1;
dp[len] = s[1];
for(int i = 2;i <= L;i++){
if(s[i] > dp[len]){ //如果大于当前数列中最后一个数,则前面的数列加上当前数列可以组成一个递增序列。
dp[++len] = s[i];
}else{ //否则就将当前这个数替换到前面数列的合适位置中,为下一个递增数的加入提供便利。
ll = 1;rr = len;
while(ll <= rr){
mm = (ll + rr) / 2;
if(dp[mm] < s[i]){
ll = mm + 1;
}else{
rr = mm - 1;
}
}
dp[ll] = s[i];
}
}
printf("%d\n",len);
}
return 0;
}
/*
总结:
1.使用一个dp数组,dp[i]表示长度为i的上升子序列结尾元素的最小值,对于一个上升子序列,显然其结尾元素越小,越有利于在后面接其他的元素,也就越可能变得更长。(贪心算法思维)
2.其中使用len保存当前能遍历到的序列中够组成的最长的子序列。
3.根据以上,我们只需要维护一个dp数组即可,对于原s[i]中的每一个值,如果s[i]大于dp[len],那我们直接将s[i]加入dp中即可;
4.如果s[i]小于dp[len]呢?那么就去dp数组中找到一个个大于s[i]的数dp[tem],并更新这个数dp[tem]为s[i],这样做是为了向后查找时,让其他元素更有利于接在其后面!
5.OK,到这里就理解到了。
*/