04_最长上升子序列问题(LIS)

来源:刘汝佳《算法竞赛入门经典--训练指南》 P60 问题6:

问题描述:给定n个整数a1,a2,...,an,按从左到右的顺序选出尽量多的整数,组成一个上升子序列(子序列可以理解为:删除0个或多个数,其他的数顺序不变)。比如,从序列1,6,2,3,7,5中,可以选上升子序列1,2,3,5,也可以选出1,6,7;但前者更长。选出的相邻元素不能相等。

O(n^2)的时间复杂度思路分析:设d[i]为以i结尾的最长上升子序列的长度,则d[i]=Max{0,d[j](满足j<i,aj<a[i])}+1。最终的答案为Max{d[i]}。

(若LIS中的相邻元素可以相等,把“<”改为“<=”即可)。

O(nlog(n))的时间复杂度思路分析:假设经过计算出的两个状态i和j满足ai<aj && d[i]==d[j];则只需要保存ai状态即可(对于后续状态k来说,若ak>ai,则ak一定大于aj,反之则不一定)。我们可以用g[i]表示当前状态(从第一个数开始)下子序列长度为i的最小数,则每考虑后续的数加入的时候,更新g[]即可(二分查找)。(Tips:该思路只适合求最大长度问题)

例题来源:http://acm.nyist.net/JudgeOnline/problem.php?pid=17

例题:nyoj 17

单调递增最长子序列

时间限制: 3000 ms  |  内存限制:65535 KB
难度: 4
 
描述
求一个字符串的最长递增子序列的长度
如:dabdbf最长递增子序列就是abdf,长度为4 
输入
第一行一个整数0<n<20,表示有n个字符串要处理
随后的n行,每行有一个字符串,该字符串的长度不会超过10000
输出
输出字符串的最长递增子序列的长度
样例输入
3

aaa

ababc

abklmncdefg
样例输出
1

3

7

O(n^2)时间复杂度代码:

 1 #include "stdio.h"

 2 #include "string.h"

 3 

 4 #define N 10100

 5 

 6 int d[N];

 7 char str[N];

 8 

 9 int inline Max(int a,int b) { return a>b?a:b; }

10 

11 int main()

12 {

13     int T;

14     int i,j;

15     int len;

16     scanf("%d",&T);

17     while(T--)

18     {

19         scanf("%s",str);

20         len = strlen(str);

21         int ans = 0;

22         for(i=0; i<len; ++i)

23         {

24             d[i] = 1;

25             for(j=0; j<i; j++)

26             {

27                 if(str[i]>str[j])

28                     d[i] = Max(d[i],d[j]+1);

29             }

30             ans = ans>d[i]?ans:d[i];

31         }

32         printf("%d\n",ans);

33     }

34     return 0;

35 }

 

O(nlog(n))的时间复杂度代码:

 1 #include "stdio.h"

 2 #include "string.h"

 3 #define N 10005

 4 #define INF 0x3fffffff

 5 

 6 int num;  //num记录当前序列中,最长子序列的长度

 7 int g[N]; //g[i]保存当前序列中,长度为i的上升子序列的最小字符

 8 char str[N];

 9 

10 int er_fen(int l,int r,int k) //二分查找,返回值为数组g[]中小于k的最右边的数的下标

11 {

12     int mid;

13     if(k>g[r]) return r;  //都比k小,返回r

14     if(k<=g[l]) return 0; //都比k大,返回0

15     while(l+1!=r)

16     {

17         mid = (l+r)/2;

18         if(g[mid] < k)

19             l = mid;

20         else

21             r = mid;

22     }

23     return l;

24 }

25 

26 int main()

27 {

28     int T;

29     int i,k,len;

30     scanf("%d",&T);

31     getchar();

32     while(T--)

33     {

34         scanf("%s",str);

35         len = strlen(str);

36         for(i=0,num=0; i<len; i++)

37             g[i] = INF;

38         num = 1;

39         g[1] = str[0];

40         for(i=1; i<len; i++)

41         {

42             k = er_fen(1,num,(int)str[i]);

43             if(g[k+1] > str[i])

44                 g[k+1] = str[i];

45             if(k==num)

46                 num++;

47         }

48         printf("%d\n",num);

49 

50     }

51     return 0;

52 }

 

你可能感兴趣的:(序列)