51nod1134最长递增子序列(二分)

题目链接: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\n",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\n",len);
    return 0;
}
 

猜你喜欢

转载自www.cnblogs.com/xiongtao/p/9293951.html
今日推荐