1. 程式人生 > >單調遞增子序列(二)(南陽oj214)

單調遞增子序列(二)(南陽oj214)

單調遞增子序列(二)

時間限制: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
來源
上傳者

經典程式碼超時,複雜度(n*n)。

#include<stdio.h>
#include<algorithm>
using namespace std;
int a[100010];
int dp[100010];
int main()
{
	int i,j,n;
	while(scanf("%d",&n)!=EOF)
	{
		for(i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
			dp[i]=1;
		}
		for(i=n-2;i>=0;i--)
		{
			for(j=i+1;j<n;j++)
			{
				if(a[i]<a[j]&&dp[i]<dp[j]+1)
				dp[i]=dp[j]+1;
			}
		}
		sort(dp,dp+n);
		printf("%d\n",dp[n-1]);
	}
	return 0;
} 
二分查詢,複雜度n(logn)可以飄過!
#include<stdio.h>
#include<string.h>
int a[100010];
int s[100010];
int len,i;
int search(int i)
{
	int left=1,right=len;
	while(left<right)
	{
		int mid=(left+right)/2;
		if(s[mid]>a[i]) 
		    right=mid;
		else if(s[mid]==a[i])
		     return mid;
		else 
		    left=mid+1;
	}
	return left;
}
int main()
{
	int j,n;
	while(scanf("%d",&n)!=EOF)
	{
		for(i=1;i<=n;i++)
		   scanf("%d",&a[i]);
		len=1;
		s[len]=a[1];
		for(i=2;i<=n;i++)
		{
			if(a[i]>s[len])
			{
			    len++;
			    s[len]=a[i];
			}
			else
			{
				j=search(i);
				s[j]=a[i];
			}	   
		}
		printf("%d\n",len);
	}
	return 0;
}