您的位置:首页 > 产品设计 > UI/UE

最长上升子序列(Longest increasing subsequence)

2014-10-19 21:33 323 查看
问题描述
对于一串数A={a1a2a3…an},它的子序列为S={s1s2s3…sn},满足{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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: