一、概念

1.给定字符串str = "ABCDADNENXY"

子序列:从str中任意去掉若干个(含0个)字符,剩下的就是这个str的子序列,如ABC, ABXY, DADXY等,中间不必连续.

子串:和子序列不同,子串必须是连续的,如ABCD,ENXY,CDADNE都是子串,而AXY不是,因为中间断开了,把连续.

子串必定是子序列,子序列不一定是子串.

2.最长公共子序列(Longest Common Sequence)

给出字符串str1和str2,如果一个字符串s同是str1和str2的子序列,则称s为二者的公共子序列,如果s最长,则称s为最长公共子序列,即LCS.

如str1 = "ABCBDCA", str2 = "DABDA", 二者的一个公共子序列为AA,而最长公共子序列为ABDA.

再如,str1 = "BACDABC", str2 = "AXBDC", 二者的LCS不止一个,如BDC, ABC, ADC都是LCS,因此需要明确:LCS有时候不唯一.

二、LCS的长度

LCS问题可以分解为,求LCS长度,再求LCS具体是哪个字符串,求LCS长度看起来相对容易一点.

问题描述: A和B分别为长度为x和y的两个字符串,设A = a1, a2, ..., ax, B = b1, b2, ..., by,要求A和B的LCS.

思路:观察A和B的最后一个字符,如果相等则该字符一定属于LCS的一部分,否则:该字符有可能属于LCS的一部分.据此构造动态规划的状态转移方程.

具体解法:如果已经给定A和B,我们可以用LCS(x, y)表示A和B的LCS长度,下面我们求递归关系式.

1.

2.如果A和B尾部字符相同

3.如果不相同

4.递推公式的边界

5.完整的递推公式

————————————————————————————————————————————————

最终要求的为LCS(x,y)的值,在已经明确递推关系式的情况下,可以采用递归或"循环打表"的方式用代码求出LCS(x,y)的值.

代码分别如下:

#include<iostream>
#include<string.h>
using namespace std;//递归的方法
//注意 A和B分别为输入的字符串前面加上一个' '空的字符,是为了解决边界问题.
int LCS(string A, string B, int x, int y)
{if(x==0 || y==0)   //边界 return 0;else              //非边界位置 {if(A[x] == B[y]) //最后一个字符相同 return LCS(A, B, x-1, y-1) + 1;elsereturn max(LCS(A, B, x, y-1), LCS(A, B, x-1, y));}
}int main()
{string A = "BCBACABBACDX";string B = "BCXYDADJL";        // A 和 B的LCS为BCAD int x = A.length();int y = B.length();A = ' ' + A;B = ' ' + B;int result = LCS(A, B, x, y);cout << result << endl;return 0;
} 
#include<iostream>
#include<string.h>
using namespace std;//循环打表 的方式求LCS[x][y]
int main()
{   string A = "BCBACABBACDX";string B = "BCXYDADJL";     // A 和 B的LCS为BCAD int x = A.length();int y = B.length();A = ' ' + A;B = ' ' + B;int i, j;int ** LCS = new int*[x+1];for(i=0;i<=x;i++){LCS[i] = new int[y+1];for (j=0;j<=y;j++)LCS[i][j] = 0;   //LCS[i][j]用来存储 }for(i=0;i<=x;i++)for(j=0;j<=y;j++)if(i==0 || j==0)LCS[i][j] = 0;else{if(A[i] == B[j])LCS[i][j] = LCS[i-1][j-1] + 1; elseLCS[i][j] = max(LCS[i-1][j], LCS[i][j-1]);}int result = LCS[x][y];cout << result << endl;return 0;
}

三、如何求出具体的LCS

LCS长度问题已经通过递推关系式求解出来了,现在来思考如何求出具体的序列有哪些字符组成. 由于LCS的非唯一, 为了简化问题,我们先求出其中一个,如果有多个LCS不要求都求出来,求出一个即可.

对于两个字符串  A = "ABCBDAB"  和   B = "BDCABA", 由上面的代码已经求出LCS长度为4, 可以看出来LCS可以是BDAB或BCAB或BCBA等,我们的目标是求出其中任意一个.

我们回忆求LCS长度的过程,是打表求出LCS[i][j](0<=i<=x,   0<=j<=y)这个二维数组. 下面手动计算这个过程.

1.二维数组或称为表格LCS[x][y]初始化

2.逐行按照递推关系式运算,结果依次如下:

......

3.最终的表格状态为:

表格右下角的值为LCS[x][y] = 4, 我们需要考虑的是4是怎么计算出来的,反推数字4的来历,记录这个路径,就可以找规律求出其中一个LCS了.

例如,最右下角的4,由于B!=A,因此是取左边4和上面4的最大值,两个4一样大,这个也从侧门反映了这个球LCS的问题的LCS不唯一.

那么我们的代码是怎么计算的呢,看一下代码

if(A[i] == B[j])LCS[i][j] = LCS[i-1][j-1] + 1;
elseLCS[i][j] = max(LCS[i-1][j], LCS[i][j-1]);

对于(i, j)位置,

如果A[i]==B[j],那么左上方向的数据+1,填到(i, j)位置

否则左边和上边两个方向的最大值,填到(i, j)位置

对于(i, j) = (7, 6),即最右下角,A[7]!=B[6],所以看LCS[6][6]和LCS[7][5],这两个值都是4,怎么办?我们的代码是取

max(LCS[i-1][j], LCS[i][j-1])

那我们怎么记录(7, 6)位置的4是从左边还是从上面来的呢,随便取一个就可以。比如,在遇到max里面两个都相等的时候,取上面的那个,

那么这个4的得到的过程如下图所示:

反推得到的路径为  结束,如果我们遍历一下这个路径(i,j),打印出满足A[i]=B[j]的字符,得到的是:BCBA,这刚好是要求的LCS之一,求出一个即可.

所以,在“循环打表”的代码基础上记录路径就可以得到诸多LCS其中的一个了.

代码如下:

#include<iostream>
#include<string.h>
using namespace std;//循环打表 的方式求LCS[x][y]
int main()
{
//  string A = "ABCBDAB";
//  string B = "BDCABA";string A = "ABCBDABXBXZWUNBV";string B = "BDCABAXWBVQUADABA";int x = A.length();int y = B.length();A = ' ' + A;B = ' ' + B;int i, j;int ** LCS = new int*[x+1];int ** dir = new int*[x+1];//dir用于记录方向 ,规定该数组元素取值只有0 1 2三种,分别表示左上,左,上 //dir[i][j]表示LCS[i][j]是从哪个方向得到的 for(i=0;i<=x;i++){LCS[i] = new int[y+1];dir[i] = new int[y+1];for (j=0;j<=y;j++)LCS[i][j] = 0;  //}for(i=0;i<=x;i++)for(j=0;j<=y;j++)if(i==0 || j==0)LCS[i][j] = 0;else{if(A[i] == B[j]){LCS[i][j] = LCS[i-1][j-1] + 1; dir[i][j] = 0;  //左上 }else{LCS[i][j] = max(LCS[i-1][j], LCS[i][j-1]);if(LCS[i-1][j]>=LCS[i][j-1])//如果>=改为>,得到的LCS不一样 dir[i][j] = 1; //i变化  上 elsedir[i][j] = 2;    //j变化  左 } }int result = LCS[x][y];cout << result << endl;//根据dir求出路径,即一系列(i,j), 同时判断 A[i]==B[j]i = x, j = y;string lcs = "";while(!(i==0 || j==0)){cout << i << " " << j << endl;if(A[i]==B[j]){lcs = A[i] + lcs;cout << A[i] << endl; } if(dir[i][j]==0)i--, j--;else if(dir[i][j]==1)i--;elsej--;}cout << lcs << endl;return 0;
}

这样可以求出一个LCS,至于如何求出所有的LCS问题,后续再讨论.

最长公共子序列(LCS)相关推荐

  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. 最长公共子序列php,动态规划(最长公共子序列LCS)

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

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

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

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

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

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

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

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

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

  10. 相似度:最长公共子序列--LCS

    一.概念 1.子序列 一个特定序列的子序列就是将给定序列中零个或多个元素去掉后得到的结果(不改变元素间相对次序).如序列[A,B,C,B,D,A,B]的子序列有:[A,B],[B,C,A],[A,D, ...

最新文章

  1. 我是怎样成长为系统架构师的
  2. 62 Celery远程调用
  3. java 线程的几种状态
  4. promethues集成nomad
  5. 现代农业谋定县域经济-农业大健康·万祥军:载体幸福美丽
  6. EasyUI中layout布局的简单使用
  7. C# Image 、 byte[] 、Bitmap之间的转化
  8. 【SIS-OAS 1.52.0】【C03-测试报告】常规版本回归测试报告-------回归测试报告模板...
  9. svn://127.0.0.1/shop
  10. 用PHPMailer在本地win环境,可以接收到邮件和附件,但在linux环境只能接收邮件信息接不到附件,是我的路...
  11. 包含min函数的栈 【微软面试100题 第二题】
  12. linux信号常用函数
  13. 找企业网站源码学习研究
  14. 校招软件测试面经篇二(国企、银行、运营商等)
  15. python读取mt4数据_将国内A股数据接入MT4平台
  16. elasticsearch创建索引和mapping
  17. VaR的应用:选择5家上市商业银行的股票交易致据(最近3年)使用 Weibull分布法估计其90天周期95%置信水平的VaR序列,并面出VaR时序图,计算每支股票最近3年内肤幅超过VaR预测园值的次
  18. 十秒清理电脑垃圾文件
  19. idea 关于自动导包的设置
  20. rtx java_如何使用JAVAWEB集成RTX推送消息

热门文章

  1. 转:UML图中类之间的关系:依赖,泛化,关联,聚合,组合,实现
  2. c++网络编程:实现简单的聊天——基于服务器/客户端的模式
  3. 杭州阿涩:关于银行业绩下降的分析
  4. 快手登录不了怎么办显示服务器繁忙,你的快手账号异常请重新登录是怎么回事...
  5. 项目管理工作一点感悟
  6. 七夕给女朋友做的一个小礼物
  7. 泰捷视频电脑版 v1.4.4 官方版
  8. tp-link无线路由器如何限制别人网速
  9. 10个3分钟锁住健康
  10. The puzzle of eggs and floors