关于一个数组的最大递增子序列的个数,首先有一个特别容易理解的方法。
用dp的思想去找以下标i结束的最大递增递减序列个数。持续更新状态;
o(n^2); 时间复杂度高,有些题不能满足。
int o[N],dp[N];//o为数组 dp以下标i结尾的最大子序列长度初值都为1
//因为每个数自身就是一个数列
for(int i=1;i<=n;i++)
for(int j=1;j<i;j++)
{
if(o[i]>o[j]) dp[i]=max(dp[i],dp[j]+1);//递增
/*
if(o[i]<o[j]) dp[i]=max(dp[i],dp[j]+1);//递减
*/
}
/*
所有的求完之后再遍历一遍找出最大值就行
也可以和dp过程合并;
*/
还有一种时间复杂度为o(n*logn),应该也是目前一个好的算法。
*********************************************************************************************************
再说之前先补充一个知识点
p=lower_bound(o,o+n,a)-o;
//p就相当于用二分查找数组o中第一个大于等于a的数的下标,
p=upper_bound(o,o+n,a)-o;
//p就相当于用二分查找数组o中第一个大于a的数的下标,
这两个就差一个等号
p=lower_bound(o,o+n,a,greater<int>())-o;
//p就相当于用二分查找数组o中第一个小于等于a的数的下标,
p=upper_bound(o,o+n,a,greater<int>())-o;
//p就相当于用二分查找数组o中第一个小于a的数的下标,
不过有一部分大佬觉得手动模拟的比这个稍微快一点。
在这的基础上就更方便实现这个子序列
这个东西也是很方便的,在平常做题也是一个很好的选择,而且二分算法是比较省时间的,特别是一些多实例,
***********************************************************************************************************
然后就是这个问题的核心代码,建议认真看。
int o[N];//数组
int dp[N];//状态存储
int len=1;//最大子序列的长度
//先把第一个数放进去
dp[1]=o[1];
for(int i=2;i<=n;i++)
{
if(o[i]>dp[len]) dp[++len]=o[i];//符合情况直接放入dp
else
{
int p=lower_bound(dp+1,dp+1+len,o[i])-dp;//找出dp中第一个大于等于o[i]的数的下标
dp[p]=o[i];//用o[i]替换
}
}
cout<<len<<endl;//len就是所求的最大长度
/*如过求的是递减、最大不增加、最大不减少序列,只需要稍微改动即可
如果一下看不懂,推荐自己模拟一下这个代码的运行过程,更好的去理解,然后自己手动敲一次代码