问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij=yj。例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列。

考虑最长公共子序列问题如何分解成子问题,设A=“a0,a1,…,am-1”,B=“b0,b1,…,bm-1”,并Z=“z0,z1,…,zk-1”为它们的最长公共子序列。不难证明有以下性质:

(1) 如果am-1=bn-1,则zk-1=am-1=bn-1,且“z0,z1,…,zk-2”是“a0,a1,…,am-2”和“b0,b1,…,bn-2”的一个最长公共子序列;

(2) 如果am-1!=bn-1,则若zk-1!=am-1,蕴涵“z0,z1,…,zk-1”是“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一个最长公共子序列;

(3) 如果am-1!=bn-1,则若zk-1!=bn-1,蕴涵“z0,z1,…,zk-1”是“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一个最长公共子序列。

这样,在找A和B的公共子序列时,如有am-1=bn-1,则进一步解决一个子问题,找“a0,a1,…,am-2”和“b0,b1,…,bm-2”的一个最长公共子序列;如果am-1!=bn-1,则要解决两个子问题,找出“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一个最长公共子序列和找出“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一个最长公共子序列,再取两者中较长者作为A和B的最长公共子序列。

求解:

引进一个二维数组c[][],用c[i][j]记录X[i]与Y[j] 的LCS 的长度,b[i][j]记录c[i][j]是通过哪一个子问题的值求得的,以决定搜索的方向。
我们是自底向上进行递推计算,那么在计算c[i,j]之前,c[i-1][j-1],c[i-1][j]与c[i][j-1]均已计算出来。此时我们根据X[i] = Y[j]还是X[i] != Y[j],就可以计算出c[i][j]。

问题的递归式写成:

回溯输出最长公共子序列过程:

算法分析:
由于每次调用至少向上或向左(或向上向左同时)移动一步,故最多调用(m + n)次就会遇到i = 0或j = 0的情况,此时开始返回。返回时与递归调用时方向相反,步数相同,故算法时间复杂度为Θ(m + n)。

http://blog.csdn.net/yysdsyl/article/details/4226630

一切没有code的分析都是耍流氓。。。 上code

void printLCS(string str1, string str2, vector<vector<int> >flag, int idx1, int idx2)
{if(idx1 == 0 || idx2 == 0 ) return;if(flag[idx1][idx2] == 1){   printLCS(str1, str2,flag, idx1-1, idx2-1);cout << idx1 <<"\t"<< idx2 <<"\t";cout << str1[idx1-1] <<"\t"<<endl;}   else if(flag[idx1][idx2] == 2)printLCS(str1, str2,flag, idx1, idx2-1);else if(flag[idx1][idx2] == 3)printLCS(str1, str2,flag, idx1-1, idx2);
}int lcs(string str1, string str2)
{const size_t len1 = str1.size();const size_t len2 = str2.size();if(len1 == 0 || len2 == 0)return 0;int f[len1 + 1][len2 + 1];vector<vector<int> >flag;vector<int> tmp;tmp.resize(len2+1);for(size_t i = 0; i<= len1; i++)flag.push_back(tmp);//memset(flag,0,sizeof(flag)); // 1: leftup; 2: left; 3: upfor(size_t i = 0; i <= len1; i++){f[i][0] = 0;}for(size_t i = 0; i <= len2; i++){f[0][i] = 0;}for(size_t i = 1; i <= len1; i++){for(size_t j = 1; j <= len2; j++){if(str1[i-1] == str2[j-1]){f[i][j] = f[i-1][j-1] + 1;flag[i][j] = 1;}else{f[i][j] = max(f[i][j-1], f[i-1][j]);if(f[i][j-1] > f[i-1][j])flag[i][j] = 2;elseflag[i][j] = 3;}}}
#if 0for(size_t i = 1; i <= len1; i++){for(size_t j = 1; j <= len2; j++){//cout << "f["<<j<<"][" <<i<<"]" << f[j][i] <<"\n";cout << f[i][j] <<"\t";}cout << endl;}cout << endl;for(size_t i = 1; i <= len1; i++){for(size_t j = 1; j <= len2; j++){//cout << "f["<<j<<"][" <<i<<"]" << f[j][i] <<"\n";cout << flag[i][j] <<"\t";}cout << endl;}
#endifprintLCS(str1, str2, flag, len1, len2);return f[len1][len2];}

最长公共字串:

找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的。其实这又是一个序贯决策问题,可以用动态规划来求解。我们采用一个二维矩阵来记录中间的结果。这个二维矩阵怎么构造呢?直接举个例子吧:"bab"和"caba"(当然我们现在一眼就可以看出来最长公共子串是"ba"或"ab")

   b  a  b

c  0  0  0

a  0  1  0

b  1  0  1

a  0  1  0

我们看矩阵的斜对角线最长的那个就能找出最长公共子串。

不过在二维矩阵上找最长的由1组成的斜对角线也是件麻烦费时的事,下面改进:当要在矩阵是填1时让它等于其左上角元素加1。

   b  a  b

c  0  0  0

a  0  1  0

b  1  0  2

a  0  2  0

这样矩阵中的最大元素就是 最长公共子串的长度。

在构造这个二维矩阵的过程中由于得出矩阵的某一行后其上一行就没用了,所以实际上在程序中可以用一维数组来代替这个矩阵。

与Subsequence问题不同的是,Substring问题不光要求下标序列是递增的,还要求每次

递增的增量为1, 即两个下标序列为:

<i, i+1, i+2, ..., i+k-1> 和 <j, j+1, j+2, ..., j+k-1>

类比Subquence问题的动态规划解法,Substring也可以用动态规划解决,令

c[i][j]表示Xi和Yi的最大Substring的长度,比如

X = <y, e, d, f>

Y = <y, e, k, f>

c[1][1] = 1

c[2][2] = 2

c[3][3] = 0

c[4][4] = 1

 动态转移方程为:

   如果xi == yj, 则 c[i][j] = c[i-1][j-1]+1

   如果xi ! = yj,  那么c[i][j] = 0

最后求Longest Common Substring的长度等于

max{  c[i][j],  1<=i<=n, 1<=j<=m}

完整的代码如下:

/**
找出两个字符串的最长公共连续子串的长度
** author :liuzhiwei
** data   :2011-08-16
**/
#include "stdio.h"
#include "string.h"
#include "stdlib.h"int longest_common_substring(char *str1, char *str2)
{int i,j,k,len1,len2,max,x,y;len1 = strlen(str1);len2 = strlen(str2);int **c = new int*[len1+1];for(i = 0; i < len1+1; i++)c[i] = new int[len2+1];for(i = 0; i < len1+1; i++)c[i][0]=0;        //第0列都初始化为0for(j = 0; j < len2+1; j++)c[0][j]=0;        //第0行都初始化为0 max = -1;for(i = 1 ; i < len1+1 ; i++){for(j = 1; j < len2+1; j++){if(str1[i-1]==str2[j-1])     //只需要跟左上方的c[i-1][j-1]比较就可以了c[i][j]=c[i-1][j-1]+1;else                         //不连续的时候还要跟左边的c[i][j-1]、上边的c[i-1][j]值比较,这里不需要c[i][j]=0;if(c[i][j]>max){max=c[i][j];x=i;y=j;}}}//输出公共子串char s[1000];k=max;i=x-1,j=y-1;s[k--]='\0';while(i>=0 && j>=0){if(str1[i]==str2[j]){s[k--]=str1[i];i--;j--;}else       //只要有一个不相等,就说明相等的公共字符断了,不连续了break;}printf("最长公共子串为:");puts(s);for(i = 0; i < len1+1; i++)         //释放动态申请的二维数组
        delete[] c[i];delete[] c;return max;
}
int main(void)
{char str1[1000],str2[1000];printf("请输入第一个字符串:");gets(str1);printf("请输入第二个字符串:");gets(str2);int len = longest_common_substring(str1, str2);printf("最长公共连续子串的长度为:%d\n",len);system("pause");return 0;
}

转载于:https://www.cnblogs.com/diegodu/p/4248242.html

最长公共子序列(LCS)问题 Longest Common Subsequence 与最长公告字串 longest common substr...相关推荐

  1. 动态规划算法解最长公共子序列LCS问题

    动态规划算法解LCS问题 作者 July 二零一零年十二月三十一日 本文参考:微软面试100题系列V0.1版第19.56题.算法导论.维基百科. 第一部分.什么是动态规划算法 ok,咱们先来了解下什么 ...

  2. 动态规划之最长公共子序列(LCS)

    最长公共子序列(LCS,Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最 ...

  3. 程序员编程艺术第十一章:最长公共子序列(LCS)问题

    程序员编程艺术第十一章:最长公共子序列(LCS)问题 0.前言 程序员编程艺术系列重新开始创作了(前十章,请参考程序员编程艺术第一~十章集锦与总结).回顾之前的前十章,有些代码是值得商榷的,因当时的代 ...

  4. 算法之最长公共子序列(LCS)问题

    算法课上老师留的作业,最长公共子序列LCS(Longest Common Subsequence)问题,首先看到这个问题感觉有点复杂,和最长公共子串不同,公共子序列并不要求元素相邻,看起来只有穷举才能 ...

  5. 动态规划表格法解决最长公共子序列(LCS)问题

    3.5 最长公共子序列(LCS) 前言:图片是博主自己画的,转载请注明出处哦 3.5.1 问题描述 最长公共子序列(Longest Common Subseuence,LCS)问题:给定两个字符串,求 ...

  6. 最长公共子序列 (LCS) 详解+例题模板(全)

    欢迎访问https://blog.csdn.net/lxt_Lucia-- 宇宙第一小仙女\(^o^)/-萌量爆表求带飞=≡Σ((( つ^o^)つ~ dalao们点个关注呗- ------------ ...

  7. 【Python】最长公共子序列LCS

    LCS的定义 最长公共子序列,即Longest Common Subsequence,LCS. 一个序列S任意删除若干个字符得到新序列T,则T叫做S的子序列: 两个序列X和Y的公共子序列中,长度最长的 ...

  8. python实现求解最长公共子序列LCS问题

    在实现论文<Automatically Generating Models for Botnet Detection>论文的算法中,用到了一个The longest commom subs ...

  9. 算法导论-----最长公共子序列LCS(动态规划)

    目录 一.概念梳理 二.最长公共子序列解决方案 方案1:蛮力搜索策略 方案2:动态规划策略 三.C代码实现 实现1 实现2(空间优化) 一.概念梳理   1. 子序列(subsequence): 一个 ...

  10. 最长公共子序列php,动态规划(最长公共子序列LCS)

    概念 求解决策过程最优化的结果 (可能有多个) 把多阶段过程转化为一系列单阶段过程,利用各阶段之间的关系,逐个求解 计算过程中会把结果都记录下,最终结果在记录中找到. 举例 求两个字符串的最长公共子序 ...

最新文章

  1. 一篇文章让你轻松搞定SpringBoot和SpringCloud之间的版本选择!!!
  2. java使用localstorage_sessionStorage和localStorage的使用
  3. java学习(115):math方法
  4. sharepoint安装心得_过程
  5. HDU 1159 Common Subsequence 动态规划
  6. vm虚拟机联网最简单的方式
  7. centos mysql mongodb_MySQL与MongoDB
  8. java 二维数组对角线_二维数组(矩阵)对角线输出
  9. html 前端传入后台为object_浅谈Object.defineProperty()
  10. [转载] 【Python】向json文件中追加新的对象
  11. 相机标定的来龙去脉(详解标定原理、畸变矫正原理、使用经验)
  12. VTK(五)---内窥镜漫游(基于VMTK血管中心线提取)
  13. 京东Java面试题、笔试题(含答案)
  14. mysql批量sql语句 c_Mysql批量插入数据sql语句
  15. 【清澄】A1013. 进制转换4
  16. HE4484E芯片资料
  17. 一般计算机电源多大,【小知识】台式机电源选多大才够?
  18. 根据TXT文件中的文件名复制文件
  19. Linux软件包安装与卸载
  20. 基于深度对抗学习的智能模糊数据生成方法

热门文章

  1. 2022-2028年中国冶金工业节能减排投资分析及前景预测报告
  2. 2022-2028年中国手机配件行业发展前景战略及投资风险预测分析报告
  3. 2022-2028年中国文化创意产业园区域发展模式与产业整体规划研究报告
  4. debian 10 ssh简单配置
  5. 【Spring】基于注解的IOC案例
  6. 确定修改——取消修改
  7. WSL 或者ubantu安装 apt-get install npm 失败解决方法
  8. 数组的拼接合并 numpy
  9. PyTorch的十七个损失函数
  10. LeetCode简单题之合并两个链表