问题描述
        对于一串数A={a1a2a3an}它的子序列为S={s1s2s3sn},满足{s1<s2<s3<<sm}。求A的最长子序列的长度。

 

 

大致的思路都是:

动态规划法

算法描述:
        设数串的长度为n,L[i]为以第i个数为末尾的最长上升子序列的长度,a[i]为数串的第i个数。
        L[i]的计算方法为:从前i-1个数中找出满足a[j]<a[i](1<=j<i)条件的最大的L[j],L[i]等于L[j]+1。
动归表达式:

 

但我想到了另外一种算法。

假设这一组数列里面最大的数是max。。那么就是求以1到max为结尾的数列的最大长度。。比如1,4,6,8就是以8结尾的数列,他的长度是4。假设max在数列里面的位置是k。我们在位置k的左边找到了一个数据max-1。。那么,以max为结尾的最大数列的长度是不是就是以max-1为结尾的数列长度加一。同理,以max-1为结尾的最大数列的长度是不是就是以max-2为结尾的数列长度加一。这种规律一直到最后,就可以从以1为结尾的数列开始往上算。
 
把这种思维简化成数据就是:
设数串的长度为n,L[x]为以x为末尾的最长上升子序列的长度。x在数列中的位置为k。
L[i]的计算方法为:从前k-1个数中找出满足a[i]<x(1<=i<k)条件的最大的L[i],L[k]等于L[i]+1。

虽然代码写起来比刚才那个复杂一点点。但是个人认为相对来说比较好理解。

 

#include "stdafx.h"
#include <stdio.h>

 int main()
{   

	int a[7];
	int max ;
	int num ;
	int len[1000] = {0};//先把长度数组赋0
	int i, j,k;
	int maxlen = 0;
	int temp = 0;

	scanf("%d",&num);

	//先找出最大值,确定循环次数。
		scanf("%d",&a[0]);
	max = a[0];
	for (i = 1; i < num; i++)
	{
		scanf("%d",&a[i]);
		max = max>a[i]?max:a[i];
	}

	//计算以i为结尾的最长上升子序列的长度
	for (i = 1; i <= max; i++)
	{
		temp = 0;//标记数列中是否存在这个数
		for (j = num;j >= 0;j--)//找出数据i在数列中的位置,让j记录
		{
			if (a[j] == i) 
			{
				temp = 1;
				break;
			}
		}
		//如果数据i存在,则开始从i所在的位置往前寻找符合条件的长度
		if(temp == 1)
		{
			for (k = j;k >= 0;k--)
			{
				if (a[k]<i&&len[a[k]]>len[i])//如果位置k(k<j)的数据小于i,比较以a[k]结尾的数列长度大于以i结尾的数列。那么,赋值过去。
				{
					len[i] = len[a[k]];
				}
			}
			len[i]++;//以max为结尾的最大数列的长度就是以一个小于max的数结尾的最大数列长度加一
			if (len[i] > maxlen)
			{
				maxlen = len[i];
			}
		}
	}
	printf("%d\n",maxlen);
	return 0;
}


 

 

 

 

posted on 2014-10-19 21:33  zkkkkkky  阅读(192)  评论(0编辑  收藏  举报