问题描述
对于一串数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。
设数串的长度为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;
}