求取最长公共子序列

article/2025/9/6 11:33:43

前言

LCS可以描述两段文字之间的“相似度”,即它们的雷同程度,从而能够用来辨别抄袭。另一方面,对一段文字进行修改之后,计算改动前后文字的最长公共子序列,将除此子序列外的部分提取出来,这种方法判断修改的部分,往往十分准确。

算法介绍

子序列:一个序列S任意删除若干个字符得到新序列T。

公共子序列:两个序列X和Y中都存在的项组成的序列。

最长公共子序列:两个序列X和Y的公共子序列中最长的序列。

例如:

字符串13455与245576的最长公共子序列为455

字符串acdfg与adfc的最长公共子序列为adf

 求取算法详解

第一种:自定义暴力求取方式

假定字符串X,Y的长度分别为m,n

X的一个子序列即下标序列{1, 2, …, m}的严格递增子序列,因此,X共有2m个不同子序列;同理,Y有2n个不同子序列,从而穷举搜索法需要指数时间O(2m*2n);

对X的每一个子序列,检查它是否也是Y的子序列,从而确定它是否为X和Y的公共子序列,并且在检查过程中选出最长的公共子序列;

显然,不可取。

针对该种算法进行改良,只对第一组数据进行依次列出,然后与第二组进行比较。其时间复杂度虽然也很高,但与2m*2n相比还是要少一些。

void lscChangeViolence(int *X, int *Y, int m) {int *AllX, *AllFlag, *result;AllX = (int*)malloc(sizeof(int)*m);AllFlag = (int*)malloc(sizeof(int)*m);result = (int*)malloc(sizeof(int)*m);for (int i = 0; i < m; i++) {AllX[i] = 0;AllFlag[i] = 0;result[i] = -1000;}int count = 1;while (count < pow(2, m)) {int num = 0;// 按照取某一位的值和不取某一位的值,将X中的某些值赋值给AllXfor (int i = 0; i < m; i++) {			if (((count >> i) & 1) == 1) {AllX[num] = X[i];num++;}}// 给定比较数组int *compare;compare = (int*)malloc(sizeof(int)*(num));for (int i = 0; i < num; i++) {compare[i] = AllX[i];}int comNum = 0;int jump = 0;int maxNum = -1;int start = 0;// 如果子数组与第二组匹配上,则记录长度,并记下数据for (int i = 0; i < num; i++) {if (start > n) {break;}for (int j = start; j < n; j++) {if (compare[i] == Y[j]) {start = j + 1;comNum++;break;}}if (comNum == i) {break;}}if (comNum > maxNum) {maxNum = comNum;for (int k = 0; k < maxNum; k++) {result[k] = compare[k];}}count++;}for (int i = 0; i < 5; i++) {if (result[i] != -1000) {printf("result[%d]=%d\n", i, result[i]);}}
}

第二种:动态规划法

字符串X,长度为m,从1开始数;

字符串Y,长度为n ,从1开始数;

LCS(X , Y) 为字符串X和Y的最长公共子序列。

若xm=yn(最后一个字符相同),则:Xm与Yn的最长公共子序列Zk的最后一个字符必定为xm或yn。

LCS(Xm , Yn) = LCS(Xm-1 , Yn-1) + xm

若xm≠yn,则:要么LCS(Xm,Yn)=LCS(Xm-1, Yn),要么LCS(Xm,Yn)=LCS(Xm, Yn-1)。

则:

LCS(X_{m},Y_{n})=\left\{\begin{matrix}LCS(X_{m-1},Y_{n-1}) \\ max\left \{ LCS(X_{m-1},Y_{n}),LCS(X_{m},Y_{n-1}) \right \} \end{matrix}\right.\begin{matrix} x_{m}=y_{n} \\ x_{m}\neq y_{n} \end{matrix}   

使用二维数组C[m,n]。

c[i,j]记录序列Xi和Yj的最长公共子序列的长度。

当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故c[i,j]=0。

c(i,j)=\left\{\begin{matrix} 0\\ c(i-1,j-1)\\ max\left \{ c(i-1,j),c(i,j-1)) \right \} \end{matrix}\right.\begin{matrix} i=0,j=0\\ i>0,j>0,x_{i}=y_{j}\\ i>0,j>=0,x_{i}\neq y_{j} \end{matrix}

使用二维数据B[m,n],其中,b[i,j]标记c[i,j]的值是由哪一个子问题的解达到的。即c[i,j]是由c[i-1,j-1]+1或者c[i-1,j]或者c[i,j-1]的哪一个得到的。取值范围为Left,Top,LeftTop三种情况。
 

// 根据规则将c[i][j]进行赋值,获取方向数组b[i][j]
void lcs_length(char *X, char *Y, int mLength, int nLength,int **C,char **B) {int num = 0;for (int i = 1; i < mLength + 1; i++) {for (int j = 1; j < nLength + 1; j++) {if (X[i-1] == Y[j-1]) {C[i][j] = C[i - 1][j - 1] + 1;B[i][j] = 'x';}else if (C[i - 1][j] >= C[i][j - 1]) {C[i][j] = C[i - 1][j];B[i][j] = 's';}else {C[i][j] = C[i][j - 1];B[i][j] = 'z';}}}for (int i = 0; i < mLength + 1; i++) {for (int j = 0; j < nLength + 1; j++) {printf("C[%d][%d]=%d  ", i, j, C[i][j]);}printf("\n");}}

下面打印最长公共子序列

// 从最后的位置进行索引,按照方向依次寻找数据,将标记为x的数据打印即为最长子数组
void lcsPrint(char **B, char *X, int i, int j) {if (i == 0 || j == 0) {return;}if (B[i][j] == 'x') {lcsPrint(B, X, i - 1, j - 1);printf("X[%d]=%c\n", i - 1, X[i - 1]);}else if (B[i][j] == 's') {lcsPrint(B, X, i - 1, j);}else {lcsPrint(B, X, i, j - 1);}
}

参考资料:

七月算法: https://www.julyedu.com/


http://chatgpt.dhexx.cn/article/XDfQJqFu.shtml

相关文章

最长公共子序列长度

求两个字符串的最长公共子序列长度。 输入格式: 输入长度≤100的两个字符串。 输出格式: 输出两个字符串的最长公共子序列长度。 输入样例1: ABCBDAB BDCABA输出样例1: 4输入样例2: ABACDEF PGHIK输出样例2: 0 (1条消息) HBU训练营【动态规划DP】——最长公共子序列长…

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

算法学习——java实现最长公共子序列学习——java实现最长公共子序列的算法&#xff0c; 实验目的&#xff1a; 输入两个同类型的序列&#xff0c;用动态规划的方法计算它们最长的公共子序列的长度和序列。 (推荐教程&#xff1a; Java视频教程 思考&#xff1a; 1.首先&#x…

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

目录 相关概念 子序列形式化定义&#xff1a; 公共子序列定义&#xff1a; 最长公共子序列&#xff08;以下简称LCS&#xff09;&#xff1a; 方法 蛮力法求解最长公共子序列&#xff1a; 动态规划求解最长公共子序列&#xff1a; 分析规律&#xff1a; 做法&#xff…

最长公共子序列问题 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;也称叙词表。它是…