zoukankan      html  css  js  c++  java
  • 求解线性dp的序列问题

    一.最长上升子序列(LIS)

    LIS(Longest Increasing Subsequence)最长上升子序列 
    一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。

    对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),

    这里1 <= i1 < i2 < … < iK <= N。 
    比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。

    这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8). 
    你的任务,就是对于给定的序列,求出最长上升子序列的长度。

    两种求解方法:

    one:O(n^2):

    状态设计:dp[i]代表以a[i]结尾的LIS的长度 
    状态转移:dp[i]=max(dp[i], dp[j]+1) (0<=j< i, a[j]< a[i]) 
    边界处理:dp[i]=1 (0<=j< n) 

    代码:

     1 int LIS()
     2 {
     3     int ans=1;
     4     for(int i=1;i<=n;i++)
     5     {
     6         dp[i]=1;
     7         for(int j=1;j<i;j++)
     8         {
     9             if(a[i]>a[j])
    10                 dp[i]=max(dp[i],dp[j]+1);
    11         }
    12     }
    13     for(int i=1;i<=n;i++)
    14         ans=max(ans,dp[i]);
    15     return ans;
    16 }

    two:贪心+二分

    a[i]表示第i个数据。 
    dp[i]表示表示长度为i+1的LIS结尾元素的最小值。 
    利用贪心的思想,对于一个上升子序列,显然当前最后一个元素越小,越有利于添加新的元素,这样LIS长度自然更长。 
    因此,我们只需要维护dp数组,其表示的就是长度为i+1的LIS结尾元素的最小值,保证每一位都是最小值,

    这样子dp数组的长度就是LIS的长度。

    dp数组具体维护过程同样举例讲解更为清晰。 
    同样对于序列 a(1, 7, 3, 5, 9, 4, 8),dp的变化过程如下:

    • dp[0] = a[0] = 1,长度为1的LIS结尾元素的最小值自然没得挑,就是第一个数。 (dp = {1})
    • 对于a[1]=7,a[1]>dp[0],因此直接添加到dp尾,dp[1]=a[1]。(dp = {1, 7})
    • 对于a[2]=3,dp[0]< a[2]< dp[1],因此a[2]替换dp[1],令dp[1]=a[2],因为长度为2的LIS,结尾元素自然是3好过于7,因为越小这样有利于后续添加新元素。 (dp = {1, 3})
    • 对于a[3]=5,a[3]>dp[1],因此直接添加到dp尾,dp[2]=a[3]。 (dp = {1, 3, 5})
    • 对于a[4]=9,a[4]>dp[2],因此同样直接添加到dp尾,dp[3]=a[9]。 (dp = {1, 3, 5, 9})
    • 对于a[5]=4,dp[1]< a[5]< dp[2],因此a[5]替换值为5的dp[2],因此长度为3的LIS,结尾元素为4会比5好,越小越好嘛。(dp = {1, 3, 4, 9})
    • 对于a[6]=8,dp[2]< a[6]< dp[3],同理a[6]替换值为9的dp[3],道理你懂。 (dp = {1, 3, 5, 8})

    这样子dp数组就维护完毕,所求LIS长度就是dp数组长度4。 
    通过上述求解,可以发现dp数组是单调递增的,因此对于每一个a[i],先判断是否可以直接插入到dp数组尾部,

    即比较其与dp数组的最大值即最后一位;如果不可以,则找出dp中第一个大于等于a[i]的位置,用a[i]替换之。 
    这个过程可以利用二分查找,因此查找时间复杂度为O(logN),所以总的时间复杂度为O(N*logN)

     1 int LIS()
     2 {
     3     memset(dp,inf,sizeof(dp));
     4     int pos=0;
     5     dp[0]=a[0];
     6     for(int i=1;i<=n;i++)
     7     {
     8         if(a[i]>dp[pos])
     9             dp[++pos]=a[i];
    10         else
    11             dp[lower_bound(dp,dp+pos+1,a[i])-dp]=a[i];
    12     }
    13     return pos+1;
    14 }

    二.最长公共子序列(LCS)

    在两个字符串中,有些字符会一样,可以形成的子序列也有可能相等,因此,长度最长的相等子序列便是两者间的最长公共字序列,其长度可以使用动态规划来求。

     1 int LCS()
     2 {
     3     memset(dp,0,sizeof(dp));
     4     for(int i=1;i<=n;i++)
     5     {
     6         for(int j=1;j<=n;j++)
     7         {
     8             if(a[i-1]==b[j-1])
     9                 dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
    10             else
    11                 dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
    12         }
    13     }
    14     return dp[n][n];    
    15 }

    三.最长公共上升子序列(LCIS)

    one:O(n^3)

    解析:f[i][j]表示以b[j]结尾,字符串a[i]之前的公共上升子序列最大长度;
    显然:f[i][j]>=f[i−1][j];;
    递推:若a[i]!=b[j]:f[i][j]=f[i−1[j];
    若a[i]==b[j]:f[i][j]=max(f[k][j])+1;(1<=k<=j-1&&b[j]>b[k])

     1 int LCIS()
     2 {
     3     int ans=0;
     4     for(int i=1;i<=n;i++)
     5     {
     6         for(int j=1;j<=n;j++)
     7         {
     8             if(a[i]!=b[j]) dp[i][j]=dp[i-1][j];
     9             else
    10             {
    11                 int maxx=0;
    12                 for(int k=1;k<j;k++)
    13                 {
    14                     if(b[j]>b[k])
    15                     maxx=max(maxx,dp[i-1][k]);
    16                 }
    17                 dp[i][j]=maxx+1;
    18                 ans=max(dp[i][j],ans);
    19             }
    20         }
    21     }
    22     return ans;
    23 }

    two:O(n^2)

    优化:通过记录对于当前a[i]与b[1-m]的匹配过程中的最大上升子序列mm,边记录,边更新,降低一维

     1 void LCIS()
     2 {
     3     for(int i=1;i<=n;i++)
     4     {
     5         int maxx=0;
     6         for(int j=1;j<=n;j++)
     7         {
     8             dp[i][j]=dp[i-1][j];
     9             if(a[i]>b[j])
    10                 maxx=max(maxx,dp[i-1][j]);
    11             if(a[i]==b[j])
    12                 dp[i][j]=maxx+1;
    13         }
    14     }
    15     int ans=0;
    16     for(int i=1;i<=n;i++)
    17         ans=max(ans,dp[n][i]);
    18     return ans;
    19 }
  • 相关阅读:
    xBIM 基本的模型操作
    xBIM 应用与学习 (二)
    xBIM 应用与学习 (一)
    ABP WebApi 加载错误
    ABP 数据迁移
    AutoDesk Forge 获取令牌认证
    IIS 加载 JSON 错误 404 解决办法
    ASP.NET MVC 5 ABP DataTables (二)
    ASP.NET MVC 5 ABP DataTables (一)
    Windows10卡顿,磁盘 内存占用100%或比较多
  • 原文地址:https://www.cnblogs.com/Spring-Onion/p/11355403.html
Copyright © 2011-2022 走看看