问题描述
对于一串数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; }