最长上升子序列|
给定一个长度为 N的数列,求数值严格单调递增的子序列的长度最长是多少。
输入格式
第一行包含整数 N。
第二行包含 N个整数,表示完整序列。
输出格式
输出一个整数,表示最大长度。
数据范围
1≤N≤1000
−109≤数列中的数≤109
输入样例:
7
3 1 2 1 8 5 6
输出样例:
4
解题思路:
状态表示:f[i]表示以a[i]结尾的最大上升子序列。
状态计算:在求以i结尾的最大子序列时,可以根据前一个数,也就是i-是那个数把f[i]进行分类。
j表示i前面的数,j的范围为0到i。f[i]=max(f[i],f[j]+1);这里需要注意边界值最坏的情况下,最长上升子序列为1,所以初始f[i]=1;
时间复杂度:两重循环,时间复杂度o(n^2);
完整代码:
#include<iostream>
using namespace std;
const int N=1010;
int n;
int a[N],f[N];//a[N]存储序列,f[N]存储最长上升子序列的值
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
f[i]=1;//只有一个数的情况
for(int j=0;j<i;j++)
if(a[j]<a[i])//必须满足前一个数小于后面的数
f[i]=max(f[i],f[j]+1);
}
int res=0;
for(int i=1;i<=n;i++) res=max(res,f[i]);//遍历求所有序列最大值
cout<<res<<endl;
return 0;
}
最长上升子序列||
给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。
输入格式
第一行包含整数 N。
第二行包含 N个整数,表示完整序列。
输出格式
输出一个整数,表示最大长度。
数据范围
1≤N≤100000,
−109≤数列中的数≤109
输入样例:
7
3 1 2 1 8 5 6
输出样例:
4
解题思路:
上一种方法时间复杂度为o(n^2),本题n的范围为100000,利用上一种方法会时间超限。本题采用更加直接的方法。
状态表示:q[i]存储长度为i结尾的最小值,同一长度的子序列,结尾越小越好,因为更加方便加上一个数。
状态计算:找到小于a[i]的最大值,将其放到q[i-1]的位置,在用a[i]去代替q[i];数的查找用二分来进行。
时间复杂度:o(nlogn)
完整代码:
#include<iostream>
using namespace std;
const int N=100010;
int n;
int a[N];//存储序列
int q[N];//存储不同大小下,结尾的最小值
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int len=0;//初始最大长度为0
for(int i=0;i<n;i++)
{
int l=0,r=len;
while(l<r)
{
int mid=l+r+1>>1;
if(q[mid]<a[i]) l=mid;
else r=mid-1;
}//二分查找小于a[i]的最大值
len=max(len,r+1);//更新最大长度
q[r+1]=a[i];//用a[i]代替q[r+1]
}
printf("%d\n",len);//输出最大长度
return 0;
}