zoukankan      html  css  js  c++  java
  • 最长递增子序列

    算法动态规划里的经典问题,爱奇艺的编程题,要求时间复杂度为O(n2),空间复杂度为O(1)。首先,先讲一种比较简单的思想,就是先将一个序列排序,然后求两个序列的最长公共子序列,转化为LCS问题。

    现在,来解这道题,解法是转载别人的,做一个整合吧。

    • 动态规划:

    一个各公司都喜欢拿来做面试笔试题的经典动态规划问题,互联网上也有很多文章对该问题进行讨论,但是我觉得对该问题的最关键的地方,这些讨论似乎都解释的不很清楚,让人心中不快,所以自己想彻底的搞一搞这个问题,希望能够将这个问题的细节之处都能够说清楚。

    对于动态规划问题,往往存在递推解决方法,这个问题也不例外。要求长度为i的序列的Ai{a1,a2,……,ai}最长递增子序列,需要先求出序列Ai-1{a1,a2,……,ai-1}中以各元素(a1,a2,……,ai-1)作为最大元素的最长递增序列,然后把所有这些递增序列与ai比较,如果某个长度为m序列的末尾元素aj(j<i)比ai要小,则将元素ai加入这个递增子序列,得到一个新的长度为m+1的新序列,否则其长度不变,将处理后的所有i个序列的长度进行比较,其中最长的序列就是所求的最长递增子序列。举例说明,对于序列A{35, 36, 39, 3, 15, 27, 6, 42}当处理到第九个元素(27)时,以35, 36, 39, 3, 15, 27, 6为最末元素的最长递增序列分别为
        35
        35,36
        35,36,39
        3
        3,15
        3,15,27
        3,6
    当新加入第10个元素42时,这些序列变为
        35,42
        35,36,42
        35,36,39,42,
        3,42
        3,15,42
        3,15,27,42
        3,6,42

    这其中最长的递增序列为(35,36,39,42)和(3,15,27,42),所以序列A的最长递增子序列的长度为4,同时在A中长度为4的递增子序列不止一个。

    该算法的思想十分简单,如果要得出Ai序列的最长递增子序列,就需要计算出Ai-1的所有元素作为最大元素的最长递增序列,依次递推Ai-2,Ai-3,……,将此过程倒过来,即可得到递推算法,依次推出A1,A2,……,直到推出Ai为止,

    代码如下

     1 unsigned int LISS(const int array[], size_t length, int result[])
     2 {
     3     unsigned int i, j, k, max;
     4 
     5     //变长数组参数,C99新特性,用于记录当前各元素作为最大元素的最长递增序列长度
     6     unsigned int liss[length];
     7 
     8     //前驱元素数组,记录当前以该元素作为最大元素的递增序列中该元素的前驱节点,用于打印序列用
     9     unsigned int pre[length];
    10 
    11     for(i = 0; i < length; ++i)
    12     {
    13         liss[i] = 1;
    14         pre[i] = i;
    15     }
    16 
    17     for(i = 1, max = 1, k = 0; i < length; ++i)
    18     {
    19         //找到以array[i]为最末元素的最长递增子序列
    20         for(j = 0; j < i; ++j)
    21         {
    22             //如果要求非递减子序列只需将array[j] < array[i]改成<=,
    23             //如果要求递减子序列只需改为>
    24             if(array[j] < array[i] && liss[j] + 1> liss[i])
    25             {
    26                 liss[i] = liss[j] + 1;
    27                 pre[i] = j;
    28 
    29                 //得到当前最长递增子序列的长度,以及该子序列的最末元素的位置
    30                 if(max < liss[i])
    31                 {
    32                     max = liss[i];
    33                     k = i;
    34                 }
    35             }
    36         }
    37     }
    38 
    39     //输出序列
    40     i = max - 1;
    41 
    42     while(pre[k] != k)
    43     {
    44         result[i--] = array[k];
    45         k = pre[k];
    46     }
    47 
    48     result[i] = array[k];
    49 
    50     return max;
    51 }

     

    该函数计算出长度为length的array的最长递增子序列的长度,作为返回值返回,实际序列保存在result数组中,该函数中使用到了C99变长数组参数特性(这个特性比较赞),不支持C99的同学们可以用malloc来申请函数里面的两个数组变量。

    • 贪心+二分查找:

    开辟一个栈,每次取栈顶元素s和读到的元素a做比较,如果a>s,  则加入栈;如果a<s,则二分查找栈中的比a大的第1个数,并替换。  最后序列长度为栈的长度。  
    这也是很好理解的,对x和y,如果x<y且E[y]<E[x],用E[y]替换E[x],此时的最长序列长度没有改变但序列Q的''潜力''增大。  
    举例:原序列为1,5,8,3,6,7  
    栈为1,5,8,此时读到3,则用3替换5,得到栈中元素为1,3,8,  再读6,用6替换8,得到1,3,6,再读7,得到最终栈为1,3,6,7  ,最长递增子序列为长度4。 

    第二种方法的时间复杂度平均为O(nlogn)。

    #include <iostream>
    #include <string>
    using namespace std;
    
    char sub[10002];
    int BinarySearch(char *arr,int len,char c)
    {
        int low=0,high=len-1;
        while(low<=high)
    {
        int mid=(low+high)>>1;
        if(c==arr[mid])
        return mid;
        else if(c>arr[mid]&&c<arr[mid+1])
        return mid+1;
        else if(c<arr[mid])
        high=mid-1;
        else
        low=mid+1;
    }
        return -1;
    }
    
        int main()
    {
        int t;
        cin>>t;
        while(t--)
    {
        string str;
        cin>>str;
        sub[0]=str[0];
        int size=1,len=str.size();
        for(int i=1;i<len;i++)
    {
        if(str[i]>sub[size-1])
        sub[size++]=str[i];
       else
    {
        int k=BinarySearch(sub,size,str[i]);
        if(k==-1)
        sub[0]=str[i];
    else
        sub[k]=str[i];
    }
    }
        cout<<size<<endl;
    }
        return 0;
    }
     
  • 相关阅读:
    Nginx调试入门
    Nginx自动安装脚本
    Centos7.3自动化脚本安装MySQL5.7
    复制多行内容到文本
    Windows常用命令
    C++笔试题
    loadrunner和QTP视频教程汇总
    mysql-connector-java-5.1.22下载
    struts学习笔记
    Hibernate原理
  • 原文地址:https://www.cnblogs.com/LUO77/p/4889873.html
Copyright © 2011-2022 走看看