题目描述
给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。
输入格式
第一行包含整数N。
第二行包含N个整数,表示完整序列。
输出格式
输出一个整数,表示最大长度。
数据范围
1≤N≤1000,
−109≤数列中的数≤109
样例
blablabla
算法1
(朴素dp) $O(n^2)$首先考虑状态表示,我们以数组f[i]表示已i结尾的最长上升子序列的数目,状态转移:从第一个数开始枚举,找到不超过i的最长子序列,那么f[i]=max(f[i],f[j]+1) j (1,2,3,…i-1),最后我们遍历一遍数组找到以每一个数字为最后一个数的最长上升子序列。
blablabla
时间复杂度
参考文献
C++ 代码
#include<bits/stdc++.h>
using namespace std;
int n;
const int N=1010;
int a[N],f[N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
{
f[i]=1;
for(int j=1;j<i;j++)
if(a[j]<a[i])f[i]=max(f[i],f[j]+1);
}
int res=-1;
for(int i=1;i<=n;i++)res=max(res,f[i]);
cout<<res;
return 0;
}
作者:hj
算法2
(二分优化) $O(nlogn)$我们开一个数组q[],q[i]存储i个树的子序列中最后一个数最小是多少,然后每次我们为每一个数a[i]找最长子序列时,我们二分找出小于这个树的最大值让最长上升子序列尽可能的长,
blablabla
时间复杂度
参考文献
C++ 代码
include<bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N],q[N];
int n;
int main()
{
cin>>n;
for(int i=0;i<n;i++)cin>>a[i];
int len=0;
for(int i=0;i<n;i++)
{
int l=0,r=len;
while(l<r)
{
int mid=(l+r+1)/2;
if(q[mid]<a[i])l=mid;
else r=mid-1;
}
len=max(len,r+1);
q[r+1]=a[i];
}
cout<<len;
return 0;
}
作者:hj
链接:https://www.acwing.com/solution/acwing/content/9095/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。