这篇日志主要为了记录这几天的学习成果。

最长公共子序列根据要不要求子序列连续分两种情况。

只考虑两个串的情况,假设两个串长度均为n.

一,子序列不要求连续。

(1)动态规划(O(n*n))

(转自:http://www.cnblogs.com/xudong-bupt/archive/2013/03/15/2959039.html)

    动态规划采用二维数组来标识中间计算结果,避免重复的计算来提高效率。

    1)最长公共子序列的长度的动态规划方程

    设有字符串a[0...n],b[0...m],下面就是递推公式。字符串a对应的是二维数组num的行,字符串b对应的是二维数组num的列。

    

    另外,采用二维数组flag来记录下标i和j的走向。数字"1"表示,斜向下;数字"2"表示,水平向右;数字"3"表示,竖直向下。这样便于以后的求解最长公共子序列。

代码:

 #include<stdio.h>
#include<string.h> char a[],b[];
char num[][]; ///记录中间结果的数组
char flag[][]; ///标记数组,用于标识下标的走向,构造出公共子序列
void LCS(); ///动态规划求解
void getLCS(); ///采用倒推方式求最长公共子序列 int main()
{
int i;
strcpy(a,"ABCBDAB");
strcpy(b,"BDCABA");
memset(num,,sizeof(num));
memset(flag,,sizeof(flag));
LCS();
printf("%d\n",num[strlen(a)][strlen(b)]);
getLCS();
return ;
} void LCS()
{
int i,j;
for(i=;i<=strlen(a);i++)
{
for(j=;j<=strlen(b);j++)
{
if(a[i-]==b[j-]) ///注意这里的下标是i-1与j-1
{
num[i][j]=num[i-][j-]+;
flag[i][j]=; ///斜向下标记
}
else if(num[i][j-]>num[i-][j])
{
num[i][j]=num[i][j-];
flag[i][j]=; ///向右标记
}
else
{
num[i][j]=num[i-][j];
flag[i][j]=; ///向下标记
}
}
}
} void getLCS()
{ char res[];
int i=strlen(a);
int j=strlen(b);
int k=; ///用于保存结果的数组标志位
while(i> && j>)
{
if(flag[i][j]==) ///如果是斜向下标记
{
res[k]=a[i-];
k++;
i--;
j--;
}
else if(flag[i][j]==) ///如果是斜向右标记
j--;
else if(flag[i][j]==) ///如果是斜向下标记
i--;
} for(i=k-;i>=;i--)
printf("%c",res[i]);
}

(2)转化为最长递增子序列问题,O( n*log(n) )

  (转自:http://karsbin.blog.51cto.com/1156716/966387)

  注意到num[i][j]仅在A[i]==B[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)的时间内算出。

二,子序列要求连续

(1) 暴力枚举(O(n^4))

  方法: 枚举B串所有子串,对比确定该子串是否为A串的某一子串,返回最长子串的长度。

  复杂度分析: B串子串个数为O(n^2), 确定子串是否为A 串的一部分,为O(n^2),故而总的复杂度为O(n^4)

(2) KMP优化匹配过程( O(n^3) )

  在算法一中用KMP优化子串与A串的匹配过程,可以将匹配过程优化为线性时间O(n),故而总的复杂度为O(n^3).

(3)  引入KMP( O(n^2) )

  方法: 将B串的所有后缀串(n个),与A串做KMP匹配,返回匹配过程中最长配对长度。 时间复杂度为O(n^2)

(4)  后缀数组解法(O(n*log(n)) )

  (转自:https://www.byvoid.com/blog/lcs-suffix-array)

  关于后缀数组的构建方法以及Height数组的性质,本文不再具体介绍,可以参阅IOI国家集训队2004年论文《后缀数组》(许智磊)和IOI国家集训队2009年论文《后缀数组——处理字符串的有力工具》(罗穗骞)。后缀数组可以在线性时间建立起来,DC3.

  回顾一下后缀数组,SA[i]表示排名第i的后缀的位置,Height[i]表示后缀SA[i]和SA[i-1]的最长公共前缀(Longest Common Prefix,LCP),简记为Height[i]=LCP(SA[i],SA[i-1])。连续的一段后缀SA[i..j]的最长公共前缀,就是H[i-1..j]的最小值,即LCP(SA[i..j])=Min(H[i-1..j])。

  求N个串的最长公共子串,可以转化为求一些后缀的最长公共前缀的最大值,这些后缀应分属于N个串。具体方法如下:

  设N个串分别为S1,S2,S3,...,SN,首先建立一个串S,把这N个串用不同的分隔符连接起来。S=S1[P1]S2[P2]S3...SN-1[PN-1]SN,P1,P2,...PN-1应为不同的N-1个不在字符集中的字符,作为分隔符(后面会解释为什么)。

  接下来,求出字符串S的后缀数组和Height数组,可以用倍增算法,或DC3算法。

  然后二分枚举答案A,假设N个串可以有长度为A的公共字串,并对A的可行性进行验证。如果验证A可行,A'(A'<A)也一定可行,尝试增大A,反之尝试缩小A。最终可以取得A的最大可行值,就是这N个串的最长公共子串的长度。可以证明,尝试次数是O(logL)的。

  于是问题就集中到了,如何验证给定的长度A是否为可行解。方法是,找出在Height数组中找出连续的一段Height[i..j],使得i<=k<=j均满足Height[k]>=A,并且i-1<=k<=j中,SA[k]分属于原有N个串S1..SN。如果能找到这样的一段,那么A就是可行解,否则A不是可行解。

  具体查找i..j时,可以先从前到后枚举i的位置,如果发现Height[i]>=A,则开始从i向后枚举j的位置,直到找到了Height[j+1]<A,判断[i..j]这个区间内SA是否分属于S1..SN。如果满足,则A为可行解,然后直接返回,否则令i=j+1继续向后枚举。S中每个字符被访问了O(1)次,S的长度为NL+N-1,所以验证的时间复杂度为O(NL)。

  到这里,我们就可以理解为什么分隔符P1..PN-1必须是不同的N-1个不在字符集中的字符了,因为这样才能保证S的后缀的公共前缀不会跨出一个原有串的范围。

  后缀数组是一种处理字符串的强大的数据结构,配合LCP函数与Height数组的性质,后缀数组更是如虎添翼。利用后缀数组,容易地求出了多个串的LCS,而且时空复杂度也相当优秀了。虽然比起后缀树的解法有所不如,但其简明的思路和容易编程的特点却在实际的应用中并不输于后缀树。

(4)  后缀数(O(n) )

  将A#B$作为字符串压入后缀树,找到最深的非叶节点,且该节点的叶节点既有#也有$(无#)。由于后缀树可以在线性时间建立,而且遍历后缀树需要线性时间(该后缀树中节点数目不大于 2(|A|+|B|)),故而总的时间为线性。

LCS最长公共子序列(最优线性时间O(n))的更多相关文章

  1. 算法设计 - LCS 最长公共子序列&&最长公共子串 &&LIS 最长递增子序列

    出处 http://segmentfault.com/blog/exploring/ 本章讲解:1. LCS(最长公共子序列)O(n^2)的时间复杂度,O(n^2)的空间复杂度:2. 与之类似但不同的 ...

  2. POJ 1458 Common Subsequence(LCS最长公共子序列)

    POJ 1458 Common Subsequence(LCS最长公共子序列)解题报告 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?c ...

  3. 动态规划模板2|LCS最长公共子序列

    LCS最长公共子序列 模板代码: #include <iostream> #include <string.h> #include <string> using n ...

  4. LCS 最长公共子序列

    区别最长公共子串(连续) ''' LCS 最长公共子序列 ''' def LCS_len(x, y): m = len(x) n = len(y) dp = [[0] * (n + 1) for i ...

  5. LCS(最长公共子序列问题)

    LCS(Longest Common Subsequence),即最长公共子序列.一个序列,如果是两个或多个已知序列的子序列,且是所有子序列中最长的,则为最长公共子序列. 原理:    事实上,最长公 ...

  6. LCS最长公共子序列

    问题:最长公共子序列不要求所求得的字符串在所给字符串中是连续的,如输入两个字符串ABCBDAB和BDCABA,字符串BCBA和BDAB都是他们的公共最长子序列 该问题属于动态规划问题 解答:设序列X= ...

  7. LCS最长公共子序列HDU1159

    最近一直在学习算法,基本上都是在学习动态规划以及字符串.当然,两者交集最经典之一则是LCS问题. 首先LCS的问题基本上就是在字符串a,b之间找到最长的公共子序列,比如 YAOLONGBLOG 和 Y ...

  8. POJ 2250(LCS最长公共子序列)

    compromise Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u   Descri ...

  9. LCS最长公共子序列~dp学习~4

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1513 Palindrome Time Limit: 4000/2000 MS (Java/Others ...

随机推荐

  1. Factory Girl使用

    1.使用Rspec,详见http://www.cnblogs.com/fanxiaopeng/p/3563772.html 2.在gemfile中添加 #Gemfile group :developm ...

  2. Red Gate Software 软件推荐

    这家公司的Wiki http://en.wikipedia.org/wiki/Redgate http://www.red-gate.com/products/ 好吧 就介绍点免费的 Find SQL ...

  3. 启动FM预算基金管理模块后,0L总账消失的解决办法

    只要用SE38运行一下:FMGL_CHANGE_APPL_IN_LEDGER 问题就解决了.

  4. zoj 2112 Dynamic Rankings

    原题链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112 #include<cstdio> #include ...

  5. 微软云平台媒体服务实践系列 2- 使用动态封装为iOS, Android , Windows 等多平台提供视频点播(VoD)方案

    文章微软云平台媒体服务实践系列 1- 使用静态封装为iOS, Android 设备实现点播(VoD)方案  介绍了如何针对少数iOS, Android 客户端的场景,出于节约成本的目的使用媒体服务的静 ...

  6. java 静态变量生命周期(类生命周期)

    Static: 加载:java虚拟机在加载类的过程中为静态变量分配内存. 类变量:static变量在内存中只有一个,存放在方法区,属于类变量,被所有实例所共享 销毁:类被卸载时,静态变量被销毁,并释放 ...

  7. sublime mac快捷键

    ^是control ⌥是option 打开/前往 ⌘T 前往文件 ⌘⌃P 前往项目 ⌘R 前往 method ⌘⇧P 命令提示 ⌃G 前往行 ⌘KB 开关侧栏 ⌃ ` python 控制台 ⌘⇧N 新 ...

  8. 微软职位内部推荐-SR DEV

    微软近期Open的职位: JD 如果你想试试这个职位,请跟我联系,我是微软的员工,可以做内部推荐.发你的中英文简历到我的邮箱:Nicholas.lu.mail(at)gmail.com

  9. JSON WEB TOKENS

    用JWT来保护我们的ASP.NET Core Web API   在上一篇博客中,自己动手写了一个Middleware来处理API的授权验证,现在就采用另外一种方式来处理这个授权验证的问题,毕竟现在也 ...

  10. MD5加密(C#)

    先来说说Md5 MD5为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护. md5有很多广泛的功能.大家都知道,数据库里面密码不会直接存该密码,而是加密之后的字符串.这时候你就可以把密码 ...