zoukankan      html  css  js  c++  java
  • LCS N(log (N) )

    lcs 最长公共子序列 O(nlogn)算法
    2012-08-19 21:51:27--点击数:173 更多 0
    最长公共子序列问题:
    给定2个字符串,求其最长公共子串。如abcde和dbada的最长公共字串为bd。
    动态规划:dp[i][j]表示A串前i个和B串前j个的最长公共子串的长度。
    则
    若A[i] == B[j] , dp[i][j] = dp[i-1][j-1] + 1;
    否则 dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
    时间复杂度O(N*M)。
    dp[i][j]仅在A[i]==B[j]处才增加,对于不相等的地方对最终值是没有影响的。
    故枚举相等点处可以对其进行优化。
    则对于dp[i][j](这里只计算A[i]==B[j]的i和j),取最大的dp[p][q],满足(p<i,q<j),通过二叉搜索树可以再logn的时间里获取到最大的dp[p][q],区间在[0,j)。
    这里也可将其转化为最长递增子序列问题。
    举例说明:
    A:abdba
    B:dbaaba
    则1:先顺序扫描A串,取其在B串的所有位置:
        2:a(2,3,5) b(1,4) d(0)。
        3:用每个字母的反序列替换,则最终的最长严格递增子序列的长度即为解。
    替换结果:532 41 0 41 532
    最大长度为3.
    简单说明:上面的序列和最长公共子串是等价的。
    对于一个满足最长严格递增子序列的序列,该序列必对应一个匹配的子串。
    反序是为了在递增子串中,每个字母对应的序列最多只有一个被选出。
    反证法可知不存在更大的公共子串,因为如果存在,则求得的最长递增子序列不是最长的,矛盾。
    最长递增子序列可在O(NLogN)的时间内算出。
    dp[i] = max(dp[j]+1) ( 满足 a[i] > a[j] && i > j )
    显然对于同样的如dp[k] = 3,假定k有多个,记为看k1,k2,.....,km 设k1 < k2 < .... < km
    在计算dp[i]的时候,k2,k3,....,km显然对结果没有帮助,取当前最小的k,
    满足ans[k] = p (最小的p使得dp[p]=k) ,每次二分,更新ans[dp[i]] = min(ans[dp[i]],i).
     
    ps:LCS在最终的时间复杂度上不是严格的O(nlogn),不知均摊上是不是。
    举个退化的例子:
    如A:aaa
        B:aaaa
    则序列321032103210
    长度变成了n*m ,最终时间复杂度O(n*m*(lognm)) > O(n*m)。
    这种情况不知有没有很好的解决办法。
    

      

  • 相关阅读:
    CTFHub_技能树_文件上传
    QT入门-重载的信号槽
    QT入门-自定义信号
    C++: xx does not name a type报错
    HDU1166 敌兵布阵
    洛谷P2574 XOR的艺术(线段树)
    P3373 【模板】线段树 2(板子好题)
    SP1716 GSS3
    QT入门-自定义槽函数
    Educational Codeforces Round 87 (Rated for Div. 2) D. Multiset(树状数组/好题)
  • 原文地址:https://www.cnblogs.com/wulangzhou/p/3082756.html
Copyright © 2011-2022 走看看