单调递增子序列(二)(nyoj214)

单调递增子序列(二)

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 4

描述

给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度。

如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5。

输入
有多组测试数据(<=7)
每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=100000)。
数据以EOF结束 。
输入数据保证合法(全为int型整数)!
输出
对于每组测试数据输出整形数列的最长递增子序列的长度,每个输出占一行。
样例输入
7
1 9 10 5 11 2 13
2
2 -1
样例输出
5
1

常规解法:动态规划       见单调递增最长子序列

#include <stdio.h>
#include <string.h>
int s[100005]={0};
int dp[100005]={0};
int main()
{
	int n;
	while(~scanf("%d", &n)&&n!=EOF)
	{
		int max=0;
		for(int i=0; i<n; i++)
		{
		    scanf("%d", &s[i]);
		    dp[i] = 0;
			for(int j=0; j<i; j++)
				if(s[j]<s[i] && dp[i]<dp[j]) dp[i]=dp[j];
			dp[i]++;
			if(max<dp[i]) max=dp[i];
		}
		printf("%d\n", max);
	}
	return 0;
}


虽然动归的效率不错,但是数据量达到10w级,而时间又限制在1s以内,单纯动归的效率还是不够。

动归+二分查找:

#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int dp[100010];
int binarysearch(int key,int len)
{
    int left=0,right=len-1,mid;
    while(left<=right)
    {
        mid=(left+right)/2;
        if(key==dp[mid])
            return mid;
        else if(key>dp[mid])
            left=mid+1;
        else
            right=mid-1;
    }
    return left;
}
int main()
{
    int n,i,j,k,len;
    while(scanf("%d",&n)!=EOF)
    {
        scanf("%d",&k);
        dp[0]=k;
        len=1;
        for(i=1; i<n; i++)
        {
            scanf("%d",&k);
            j=binarysearch(k,len);
            dp[j]=k;
            len=j+1>len?j+1:len;
            //for(int x=0; x<len; x++)
            //    printf("%d ", dp[x]);
            //printf("\n");
        }
        printf("%d\n",len);
    }
    return 0;
}

//测试数据:
//7
//1 9 10 5 11 2 13
//12
//1 9 10 5 11 2 13 3 4 5 6 7
//2
//2 -1



你可能感兴趣的:(动态规划,单调递增子序列)