动态规划解最长公共子序列(LCS)(附详细填表过程)

article/2025/9/6 11:36:37

目录

相关概念

子序列形式化定义:

公共子序列定义:

最长公共子序列(以下简称LCS):

方法

蛮力法求解最长公共子序列:

动态规划求解最长公共子序列:

分析规律:

做法:

伪代码:

下面演示下c数组的填表过程:(以求ABCB和BDCA的LCS长度为例):

时间复杂度:

代码:

结果示例:


相关概念

子序列形式化定义:

给定一个序列X=<x1,x2,x3,x4...,xm>,另一个序列Z=<z1,z2,z3,z4...,zk>,若存在一个严格递增的X的下标序列<i1,i2,i3,...,ik>对所有的1,2,3,...,k,都满足x(ik)=zk,则称Z是X的子序列

比如Z=<B,C,D,B>是X=<A,B,C,B,D,A,B>的子序列

公共子序列定义:

如果Z既是X的子序列,又是Y的子序列,则称Z为X和Y的公共子序列

最长公共子序列(以下简称LCS):

2个序列的子序列中长度最长的那个

方法

蛮力法求解最长公共子序列:

需要遍历出所有的可能,时间复杂度是O(n³),太慢了

动态规划求解最长公共子序列:

分析规律:

设X=<x1,x2,x3,x4...,xm>,Y=<y1,y2,y3,y4...,yn>为两个序列,Z=<z1,z2,z3,z4...,zk>是他们的任意公共子序列

经过分析,我们可以知道:

1、如果xm = yn,则zk = xm = yn 且 Zk-1是Xm-1和Yn-1的一个LCS

2、如果xm != yn 且 zk != xm,则Z是Xm-1和Y的一个LCS

3、如果xm != yn 且 zk != yn,则Z是X和Yn-1的一个LCS

所以如果用一个二维数组c表示字符串X和Y中对应的前i,前j个字符的LCS的长度话,可以得到以下公式:

文字意思就是:

p1表示X的前 i-1 个字符和Y的前 j 个字符的LCS的长度

p2表示X的前 i 个字符和Y的前 j-1 个字符的LCS的长度

p表示X的前 i-1 个字符和Y的前 j-1 个字符的LCS的长度

p0表示X的前 i 个字符和Y的前 j 个字符的LCS的长度

如果X的第 i 个字符和Y的第 j 个字符相等,则p0 = p + 1

如果X的第 i 个字符和Y的第 j 个字符不相等,则p0 = max(p1,p2)

 

做法:

因此,我们只需要从c[0][0]开始填表,填到c[m-1][n-1],所得到的c[m-1][n-1]就是LCS的长度

但是,我们怎么得到LCS本身而非LCS的长度呢?

也是用一个二维数组b来表示:

在对应字符相等的时候,用↖标记

在p1 >= p2的时候,用↑标记

在p1 < p2的时候,用←标记

伪代码:

若想得到LCS,则再遍历一次b数组就好了,从最后一个位置开始往前遍历:

如果箭头是↖,则代表这个字符是LCS的一员,存下来后 i-- , j--

如果箭头是←,则代表这个字符不是LCS的一员,j--

如果箭头是↑ ,也代表这个字符不是LCS的一员,i--

如此直到i = 0或者j = 0时停止,最后存下来的字符就是所有的LCS字符

比如说求ABCBDAB和BDCABA的LCS:

灰色且带↖箭头的部分即为所有的LCS的字符

 

下面演示下c数组的填表过程:(以求ABCB和BDCA的LCS长度为例):

以此类推

最后填出的表为:

右下角的2即为LCS的长度

 

时间复杂度:

由于只需要填一个m行n列的二维数组,其中m代表第一个字符串长度,n代表第二个字符串长度

所以时间复杂度为O(m*n)

代码:

#include <iostream>
#include <string>
#include <stack>
using namespace std;
void LCS(string s1,string s2)
{int m=s1.length()+1;int n=s2.length()+1;int **c;int **b;c=new int* [m];b=new int* [m];for(int i=0;i<m;i++){c[i]=new int [n];b[i]=new int [n];for(int j=0;j<n;j++)b[i][j]=0;}for(int i=0;i<m;i++)c[i][0]=0;for(int i=0;i<n;i++)c[0][i]=0;for(int i=0;i<m-1;i++){for(int j=0;j<n-1;j++){if(s1[i]==s2[j]){c[i+1][j+1]=c[i][j]+1;b[i+1][j+1]=1;          //1表示箭头为  左上}else if(c[i][j+1]>=c[i+1][j]){c[i+1][j+1]=c[i][j+1];b[i+1][j+1]=2;          //2表示箭头向  上}else{c[i+1][j+1]=c[i+1][j];b[i+1][j+1]=3;          //3表示箭头向  左}}}for(int i=0;i<m;i++)                //输出c数组{for(int j=0;j<n;j++){cout<<c[i][j]<<' ';}cout<<endl;}stack<char> same;                   //存LCS字符stack<int> same1,same2;             //存LCS字符在字符串1和字符串2中对应的下标,方便显示出来for(int i = m-1,j = n-1;i >= 0 && j >= 0; ){if(b[i][j] == 1){i--;j--;same.push(s1[i]);same1.push(i);same2.push(j);}else if(b[i][j] == 2)i--;elsej--;}cout<<s1<<endl;                     //输出字符串1for(int i=0;i<m && !same1.empty();i++)      //输出字符串1的标记{if(i==same1.top()){cout<<1;same1.pop();}elsecout<<' ';}cout<<endl<<s2<<endl;                //输出字符串2for(int i=0;i<n && !same2.empty();i++)      //输出字符串2的标记{if(i==same2.top()){cout<<1;same2.pop();}elsecout<<' ';}cout<<endl<<"最长公共子序列为:";while(!same.empty()){cout<<same.top();same.pop();}cout<<endl<<"长度为:"<<c[m-1][n-1]<<endl;for (int i = 0; i<m; i++){delete [] c[i];delete [] b[i];}delete []c;delete []b;
}
int main()
{string s1="ABCPDSFJGODIHJOFDIUSHGD";string s2="OSDIHGKODGHBLKSJBHKAGHI";LCS(s1,s2);return 0;
}

结果示例:


http://chatgpt.dhexx.cn/article/9OQlVaBC.shtml

相关文章

最长公共子序列问题 c语言,最长公共子序列问题C语言

最长公共子序列问题C语言 #include#include#includeint num[50][50]{0}; int b[50][50]{0}; int lcsLength(char *x,char *y,int xLen,int yLen); void LCS(int i,int j,char *x); int lcsLength(char *x,char *y,int xLen,int yLen){ int mxLen-1; int nyLen-1; for(int i0;i&…

java最长公共子序列算法_算法学习——java实现最长公共子序列

实验目的&#xff1a; 输入两个相同类型的序列&#xff0c;用动态规划方法计算他们的最长公共子序列的长度以及序列。 思路&#xff1a; 1、先用一个二维数组存储最长公共子序列的长度&#xff0c;还要记录每个值的状态 2、根据记录值的状态&#xff0c;递归回溯求出最长公共子…

python 最长公共子序列长度_python实现最长公共子序列

最长公共子序列python实现&#xff0c;最长公共子序列是动态规划基本题目&#xff0c;下面按照动态规划基本步骤解出来。 1.找出最优解的性质&#xff0c;并刻划其结构特征 序列a共有m个元素&#xff0c;序列b共有n个元素&#xff0c;如果a[m-1]b[n-1]&#xff0c;那么a[:m]和b…

算法:最长公共子序列(输出所有最长公共子序列)

问题描述&#xff1a;给定两个序列&#xff0c;例如 X “ABCBDAB”、Y “BDCABA”&#xff0c;求它们的最长公共子序列的长度。 下面是求解时的动态规划表&#xff0c;可以看出 X 和 Y 的最长公共子序列的长度为4&#xff1a; 输出一个最长公共子序列并不难&#xff08;网上…

动态规划 最长公共子序列 过程图解

1.基本概念 首先需要科普一下,最长公共子序列(longest common sequence)和最长公共子串(longest common substring)不是一回事儿。什么是子序列呢?即一个给定的序列的子序列,就是将给定序列中零个或多个元素去掉之后得到的结果。什么是子串呢?给定串中任意个连续的字符…

算法知识之最长公共子序列问题(动态规划)

最近朋友让帮做个关于动态规划的最长公共子序列的问题,翻看以前的笔记并完成该题后,顺便写这样一篇文章,希望对大家有所帮助,同时也帮助自己回顾该知识点. 一.最长公共子序列的定义 子序列:若给定序列X{x1,x2,…,xm},则另一序列Z{z1,z2,…,zk},是X的子序列是指存在一个严格递…

动态规划篇——最长公共子序列(c++)

引言&#xff1a;最长公共子序列属于动态规划的基础篇&#xff0c;由字符串的最长公共最序列可以引出很多的问题。 最长子序列详细讲解以及练习题目 需要详细讲解教程的可以观看上面链接的文章&#xff0c;以下是自己做的简单的概括。 一、何为最长公共子序列 A和B的公共子序…

最长公共子序列(LCS)

此文全文参考自&#xff1a;https://blog.csdn.net/dq_dm/article/details/45043689&#xff0c;特此感谢&#xff01; 然后自己参考了&#xff1a;http://www.ahathinking.com/archives/115.html 和July的ppt讲义《十分钟搞定LCS》&#xff0c;为表示版权&#xff0c;特地留下…

动态规划——最长公共子序列

先来讲解以下什么是最长公共子序列。最长公共子序列不是最长相同字符串&#xff0c;有点相似但不一样&#xff0c;来举个简单的例子&#xff0c;有字符串s1bcdea&#xff0c;s2abce&#xff0c;最长相同字符串是bc&#xff0c;最大公共部分是2&#xff1b;而最长公共子序列则是…

动态规划---例题2.最长公共子序列问题

本题与力扣主站1143题相同. 一.问题描述 一个给定序列的子序列是在该序列中删去若干元素后得到的序列。 确切地说&#xff0c;若给定序列X<x1, x2,…, xm>&#xff0c;则另一序列Z<z1, z2,…, zk>是X的子序列是指存在一个严格递增的下标序列 <i1, i2,…, ik&g…

知识图谱本体建模之RDF、RDFS、OWL详解

&#xff08;一&#xff09;知识图谱本体建模之RDF、RDFS、OWL详解 1.语义网体系 知识图谱于2012年由Google提出&#xff0c;并不是新概念&#xff0c;而是由语义网络(Semantic Network)衍生而来。语义网络由相互连接的节点和边组成&#xff0c;节点表示概念或者对象&#xf…

OWL本体基础知识

备注&#xff1a; OWL本体中对象属性和数据属性都可以有进一步的注释属性&#xff0c;被称之为公理 <owl:NamedIndividual rdf:about"http://www.semanticweb.org/bob/ontologies/2022/11/untitled-ontology-20#刘二菲"><like rdf:resource"http://www…

protege系列(一):本体开发101:创建第一个本体的指南

protege作为领域本体编辑工作一直为自然语言处理和语义网、知识图谱等行业人士喜爱&#xff0c;但是还没有比较完整的官方Protege中文文档&#xff0c;本系列旨在通过对protege官方网站上教程等内容的翻译和再现&#xff0c;为广大网友提供一个全面的、权威的protege教程。 本…

动态本体 palantir

102解析器与106本体耦合&#xff0c;106本体与108数据库耦合&#xff1b; 106本体有一个或多个110对象类型和116属性类型 110对象类型实例化多个112对象 每一个对象有一个或多个属性 116属性类型实例化114A和114B属性 116属性类型有一个或多个118组件&#xff0c;组件有字符串、…

什么是计算机科学中的“本体论”

最近看用户画像&#xff0c;里面提到了本体论。故把知乎一个回答放于此地。 一、本体的概念 本体的概念有两层意思&#xff0c;一层是哲学层面的意思&#xff0c;一层是引申到信息科学中的语义层面的意思。 举个最通俗的例子来解释一下这两层意思&#xff0c;我们就拿苹果来举…

本体建模学习笔记

目录 1. 语义网 & 语义网络 1.1 链接数据与知识图谱 的区别 1.2 本体构建的两种方式 1.3 知识图谱数据的来源 0. RDF、OWL 与RDFS 0.1 RDF序列化 0.2 关系 / 属性 0.3 RDFS词汇 0.4 本体映射词汇&#xff08;Ontology Mapping&#xff09; 2. Protege实现本体建模…

知识元与知识本体

元数据&#xff08;Metadata&#xff09;就是“关于数据的数据”,是对数据进行组织和处理的基础。元数据法就是对信息单元及其集合进行规范描述从而形成元数据&#xff0c;并依其将分布式的信息资源整合成有机信息体系的基准、方法和工具。主题词表&#xff1a;也称叙词表。它是…

本体语言 OWL

万维网本体语言OWL2 文章目录 万维网本体语言OWL2一、引言二、本体语言的需求三、OWL2和RDF/RDFS的兼容性3.1 OWL2 Full&#xff1a;基于RDF的语义3.2 OWL2 DL&#xff1a;直接语义 四、OWL语言五、OWL2 概要六、实验 OWL的构造七、总结 一、引言 通俗的讲&#xff0c;RDF被限…

本体概述

目录1.定义2.本体的目标和作用3.本体构成要素4.领域本体与上层本体5.本体语言6. 构造Ontology 的规则 7.本体在信息检索的应用 1.定义 – 1991/Neches 等&#xff1a;给出构成相关领域词汇的基本术语和关系&#xff0c;以及利用这些术语和关系构成的规定这些词汇外延的规则…

本体 摘抄笔记

一、本体的一些介绍 &#xff08;来源&#xff1a;https://blog.csdn.net/shendeguang/article/details/8241164&#xff09; 1. 本体论语义学的特点&#xff1a; 本体论语义学与其他人工智能理论、自然语言加工系统相比有自己的一些鲜明特点。 其一&#xff0c;它强调对意义…