题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1134
给出长度为N的数组,找出这个数组的最长递增子序列。(递增子序列是指,子序列的元素是递增的)
例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2 4 5 10。
Input
第1行:1个数N,N为序列的长度(2 <= N <= 50000) 第2 - N + 1行:每行1个数,对应序列的元素(-10^9 <= S[i] <= 10^9)
Output
输出最长递增子序列的长度。
Input示例
8 5 1 6 8 2 4 5 10
Output示例
5
一开始我是用dp写的,本来以为就是一道模板题,发现超时了,时间复杂度是o(n2),先贴下超时的代码
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; int a[50005],dp[50005]; int main() { int n,ans=0; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int i=0;i<n;i++) { dp[i]=1; for(int j=0;j<i;j++) { if(a[i]>a[j]) dp[i]=max(dp[i],dp[j]+1); } ans=max(ans,dp[i]); } printf("%d ",ans); return 0; }
之后看了博客才知道要用二分,这样时间复杂度就只有o(nlogn),要用len记录一下当前最长子序列的数量,这里用到了
二分查找的函数lower_bound(),这个函数有三个参数lower_bound(f,f+len,a[i]),f和f+len是指针,就是在f到f+len二分查找a[i]放置的位置,返回的也是指针,不会可以百度下。
代码:
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; int a[50005]; int f[50005]; int main() { int n,maxn; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&a[i]); int len=1; memset(f,0,sizeof(f));//创建一个新数组存放最长上升序列 f[0]=a[0]; for(int i=1;i<n;i++) { int pos=lower_bound(f,f+len,a[i])-f;//二分查找i+1个数中最长上升序列,a[i]的位置 f[pos]=a[i]; /*cout<<ans<<" "<<pos<<endl;*/ len=max(len,pos+1);//最长上升序列的数量 } /*for(int i=0;i<ans;i++) cout<<f[i]<<endl;*/ printf("%d ",len); return 0; }