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
",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
",num);
49 
50     }
51     return 0;
52 }

原文地址:https://www.cnblogs.com/ruo-yu/p/4384632.html