51Nod-1134 最长递增子序列

1134 最长递增子序列 

基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题

 收藏

 关注

给出长度为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

一道51上难度为0的题,结果弄得很麻烦。。。看来还是太菜了。

好了,看下题吧,求最长递增子序列,emmmmm.......基础字符串题型,最一开始用的动态规划。

↓↓↓

#include <stdio.h>
#include <string.h>
typedef long long ElemType;

int dp[50010];
long long str[50010];

int list( ElemType *c , int len ){
	memset( dp,0,sizeof(dp) );
	int max = 0;
	for( int i=1 ; i<len ; i++ ){
		for( int j=0 ; j<i ; j++ ){
			if( c[i]>c[j] && dp[i]<dp[j]+1 )
				dp[i] = dp[j] + 1;
		}
		if( max<dp[i] )
			max = dp[i];
	}
	return ++max;
}

int main(){
	int n;
	scanf( "%d",&n );
	for( int i=0 ; i<n ; i++ ){
		scanf( "%lld",&str[i] );
	}
	printf( "%d\n",list( str,n ) );
}

完美的超时了最后五组数据。。。略有一丝尴尬,,,可能是刚刚来还是不太熟悉51吧,后来借助博客上的ACM大神提点:转载大神博客 ,让我明白了二分算法的重要性。。。于是,自认为看懂了之后照这样子写了一个。。。

↓↓↓

#include <stdio.h>
#include <string.h>
#define MAXN 50010
typedef long long ElemType ; 

int n;                      //数组num的实际长度 
long long dp[MAXN];			//记录每一长度的最小末尾元素 
long long num[MAXN] ;		//初始序列 

//二分查找当前元素value应该插入的位置 
int bin_serach( ElemType *c , int len , ElemType value ){
	int left = 0 ;
	int right = len-1 ;
	int mid;
	//二分,左右游标相等时停止 
	while( left<=right ){
		mid = ( left+right )/2;
		//mid位置元素值大于value,目标位置在左半部分 
		if( c[mid]>value )
			right = mid - 1 ;
		//mid位置元素值大于value,目标位置在右半部分 
		else if( c[mid]<value )
			left = mid + 1 ;
		//mid位置元素值与value相等 ,已找到,返回mid 
		else
			return mid;
	}
	//未找到该元素,此时返回比value大的最小元素的位置,更新元素值 
	return left;
}

//求最长递增子序列的函数 
int list( ElemType *c , int n ){
	memset( dp,0,sizeof(dp) );
	int len=0;
	for( int i=0 ; i<n ; i++ ){
		//如果num[i]比当前最长长度末尾元素还大,长度+1 
		if( num[i]>dp[len] )
			dp[++len] = num[i];
		else{
			//取得元素num[i]应该插入的位置 
			int pos = bin_serach( dp,len,num[i] );
			dp[pos] = num[i];
		}
	}
	return len;
}

int main(){
	scanf( "%d",&n );
	for( int i=0 ; i<n ; i++ )
		scanf( "%lld",&num[i] );
	printf( "%d\n",list( dp,n ) ) ;
/*	for( int i=0 ; i<=list( dp,n ) ; i++ ){
		printf( "%lld ",dp[i] );
	}
	printf( "\n" );
*/
}

嗯,写的不错,测试了一下,完美通过hhhh,然后测试了第一组样例答案错误????蜜汁尴尬。。。然后用一个for循环一步一步追踪了一下dp数组,发现dp数组里有负数???好吧,我的错。。于是我找来了无穷小,然后变成了这样

↓↓↓

#include <stdio.h>
#include <string.h>
#define MAXN 50010
#define MINN 0xc0c0c0c0
typedef long long ElemType ; 

int n;                      //数组num的实际长度 
long long dp[MAXN];	    //记录每一长度的最小末尾元素 
long long num[MAXN] ;	    //初始序列 

//二分查找当前元素value应该插入的位置 
int bin_serach( ElemType *c , int len , ElemType value ){
	int left = 0 ;
	int right = len-1 ;
	int mid;
	//二分,左右游标错过时停止 
	while( left<=right ){
		mid = ( left+right )/2;
		//mid位置元素值大于value,目标位置在左半部分 
		if( c[mid]>value )
			right = mid - 1 ;
		//mid位置元素值大于value,目标位置在右半部分 
		else if( c[mid]<value )
			left = mid + 1 ;
		//mid位置元素值与value相等 ,已找到,返回mid 
		else
			return mid;
	}
	//未找到该元素,此时返回比value大的最小元素的位置,更新元素值 
	return left;
}

//求最长递增子序列的函数 
int list( ElemType *c , int n ){
	memset( dp,0xc0,sizeof(dp) );
	int len=0;
	for( int i=0 ; i<n ; i++ ){
		//如果num[i]比当前最长长度末尾元素还大,长度+1 
		if( num[i]>dp[len] )
			dp[++len] = num[i];
		else{
			//取得元素num[i]应该插入的位置 
			int pos = bin_serach( dp,len,num[i] );
			dp[pos] = num[i];
		}
	}
	return len;
}

int main(){
	scanf( "%d",&n );
	for( int i=0 ; i<n ; i++ )
		scanf( "%lld",&num[i] );
	printf( "%d\n",list( dp,n ) ) ;
/*	for( int i=0 ; i<=list( dp,n ) ; i++ ){
		printf( "%lld ",dp[i] );
	}
	printf( "\n" );
*/
}

嗯,没错,这次完美通过,下面来解释一下算法的思想,,,那num[8]={ 5,1,6,8,2,4,5,10 }来说吧。

首先len=0。list函数开始遍历num数组:

i=0时:此时dp输出都为无穷小哦,理所当然的dp[0]=5,len=1了哦(dp[]={ 5 })

i=1时:此时num[1]=1比5小,这个dp呢我们是来存储每一个长度的最小末尾的(这一句不理解没关系,接着看就理解了),此时呢len=1,而1又比5小,所以就将dp[0]=5更新为dp[0]=1(因为递增嘛,长度相同的时候当然是越小越好咯)(dp[]={ 1 })

i=2时:此时num[2]=6比1大,所以dp[1]=6,len+1,len=2了啊(dp[]={ 1,6 })

i=3时:此时num[3]=8比6大,所以dp[2]=8,len+1,len=3了哦(dp[]={ 1,6,8 })

i=4时:此时num[4]=2,而看看dp,比2大的最小的是6,于是就把len=2时的最小末尾更新为2(dp[]={ 1,2,8 })

i=5时:此时num[5]=4,看dp,把len=3时的最小末尾更新为4(dp[]={ 1,2,4 })

i=6时:此时num[6]=5,比dp最大的数还大,dp[4]=5,len+1,len=4(dp[]={ 1,2,4,5 })

i=7时:此时num[7]=10,最大的,dp[5]=10,len+1,len=5(dp[]={ 1,2,4,5,10 })

此时1,2,4,5,10就是num数组的最长递增子序列了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值