zoukankan      html  css  js  c++  java
  • 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 }

  • 相关阅读:
    Java实例_队列Queue用法
    JAVA中不同类型的取值范围
    面试被问到的题
    关于Maven启动项目各种.xml文件和.properties文件找不到问题的解决
    jupyter使用
    java中“==”和equal区别
    redis持久化的几种方式
    事务是什么,以及事务四个特性
    Java中的String类能否被继承?为什么?以及final和static的区别
    pytest.mark.parametrize 参数化
  • 原文地址:https://www.cnblogs.com/ruo-yu/p/4384632.html
Copyright © 2011-2022 走看看