24、数据结构与算法实战:最长上升子序列

Description
*

Input
输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。

Output
最长上升子序列的长度。

Sample Input

7
17 3 5 9 4 8

Sample Output

4

参考程序

#include <stdio.h>
#include <string.h>
#define LEN 1000
int max(int a,int b)
{
   
     
	return a>b?a:b;
}

int main()
{
   
     
	int a[LEN+5],dp[LEN+5],N;
	int i,j;
	scanf("%d",&N);
	for(i=0;i<N;i++)
	{
   
     
		scanf("%d",&a[i]);
		dp[i]=1;
	}
	for(i=1;i<N;i++)
	{
   
     
		for(j=0;j<i;j++)
		{
   
     
			if(a[i]>a[j])
			{
   
     
				dp[i]=max(dp[j]+1,dp[i]);
				//保证a[i]的前驱应比它小(并入序列后能成为一个上升序列),而且应该跟在dp值最大的元素后 
			}
		}
	}
	int max=-1;
	for(i=0;i<N;i++)
	{
   
     //求出dp数组中的最大值 
		if(dp[i]>max)
		{
   
     
			max=dp[i];
		}
	}
	printf("%d\n",max);
	return 0;
}

分析:这是一道动态规划问题的一道典型问题。关键问题是如何找到状态转移方程,即递推式。寻找递推式从只有一项元素的极端状态入手,逐步扩大规模发现规律。
设dp[i]表示以元素a[i]为结尾的最大递增子序列的长度.
如果只有一个元素,例如“3”,那默认为上升,即dp[0]=1.
如果有两个元素,例如“3 1”,这个序列本身就是递减的,所以1的存在并没有使得序列增长。或者说,a[i]作为某个序列的结尾,必须要添加在比它小的元素后边,这样能保证以元素a[i]为结尾的序列仍旧是递增的;然而在下标i之前,比a[i]小的元素可能有很多,那么究竟应该加在哪个元素后面呢?应当加在dp取最大值的所对应元素的后边,相当于强强联合,每一步都只并入上一步最长的序列(当然还要保证序列递增的前提下),递推下去,那么就能得出问题的全局解。

dp数组的求取借助了内外两层循环,因而算法的时间复杂度应为O(N^2)

希望大家批评指正!

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: