LCS 最长公共子序列

【Python】最长公共子序列LCS LCS的定义 最长公共子序列,即Longest Common Subsequence,LCS。 一个序列S任意删除若干个字符得到新序列T,则T叫做S的子序列; 两个序列X和Y的公共子序列中,长度最长的那个,定义为X和Y的最长公共子序列。 字符串13455 与245576的最长公共子序列为455 字符串acdfg与adfc的最长公共子序列为adf 注意区别最长公共子串(Longest C... 阅读详情

这一片文章写得非常好,放在这里。


LCS:又称 最长公共子序列。 其中子序列(subsequence)的概念不同于串的子串。它是一个不一定连续但按顺序取自字符串X中的字符序列。 例如:串"AAAG"就是串“CGATAATTGAGA”的一个子序列。

 

 

字符串的相似性问题可以通过求解两个串间的最长公共子序列(LCS)来得到。 当然如果使用穷举算法列出串的所有子序列,一共有2^n种,而每个子序列是否是另外一个串的子序列又需要O(m)的时间复杂度,因此这个穷举的方法时间复杂度是O(m*(2^n))指数级别,效率相当的可怕。我们采用动态规划算法来解决这个问题。

 

 

动态规划算法解决最长公共子序列

 

假如我们有两个字符串:X=[0,1,2....n]  Y=[0,1,2...m]。我们定义L(i, j)为X[0...i]与Y[0...j]之间的最长公共子序列的长度。通过动态规划思想(复杂问题的最优解是子问题的最优解和子问题的重叠性质决定的)。我们考虑这样两种情况:

 

(1)  当X[i]=Y[j]时, L(i, j)=L(i-1, j-1)+1 。证明很简单。

(2)  当X[i]!=Y[j]时, 说明此事X[0...i]和Y[0...j]的最长公共子序列中绝对不可能同时含有X[i]和Y[j]。那么公共子序列可能以X[i]结尾,可能以Y[j]结尾,可以末尾都不含有X[i]或Y[j]。因此

                               L(i, j)= MAX{L(i-1 , j), L(i, j-1)}



package DP;

public class LCS2 {
	/** 字符串X的字符数组 */
	private char[] charArrayX = null;
	/** 字符串Y的字符数组 */
	private char[] charArrayY = null;

	public LCS2(String sa, String sb) {
		charArrayX = new char[sa.length() + 1];
		System.arraycopy(sa.toCharArray(), 0, charArrayX, 1, sa.length());
		charArrayY = new char[sb.length() + 1];
		System.arraycopy(sb.toCharArray(), 0, charArrayY, 1, sb.length());
	}

	/**
	 * 得到最长公共子序列的长度
	 */
	public void getLCS() {

		int[][] length = new int[charArrayX.length + 1][charArrayY.length + 1];

		for (int m = 1; m < charArrayX.length; m++) {
			for (int n = 1; n < charArrayY.length; n++) {
				if (charArrayX[m] == charArrayY[n]) {
					length[m][n] = length[m - 1][n - 1] + 1;
				} else
					length[m][n] = max(length[m - 1][n], length[m][n - 1]);
//					length[m][n] = max(length[m][n], length[m-1][n-1]);
			}
		}

		for (int m = 0; m < charArrayX.length; m++) {
			for (int n = 0; n < charArrayY.length; n++) {
				System.out.print(length[m][n] + " ");
			}
			System.out.println();
		}

		// 打印最长公共子序列
		String lcstr = "";
		int x = charArrayX.length - 1;
		int y = charArrayY.length - 1;
		while (x >= 1 && y >= 1) {
			if (charArrayX[x] == charArrayY[y]) {
				lcstr = charArrayX[x] + lcstr;
				x--;
				y--;
			} else {
				if (length[x - 1][y] <= length[x][y - 1])	// 往值较大的路径走
					y--;
				else
					x--;
			}
		}
		System.out.println("最长公共子序列为:" + lcstr + " [length=" + lcstr.length()
				+ "]");
	}

	/**
	 * 取最大值
	 */
	private int max(int m, int n) {
		return m > n ? m : n;
	}

	/**
	 * 测试
	 */
	public static void main(String[] args) {
		LCS2 lcs = new LCS2("GTTCCTAATA", "CGATAATTGAGA");
		lcs.getLCS();
	}
}


这里解释一下上面的代码,其中getLength()的作用是递归获取最长公共子串的长度,并得到递归过程中每个子串之间最长公共子串长度的状态表lcs[][],这张表运行的结果如下:




C

G

A

T

A

A

T

T

G

A

G

A


0

0

0

0

0

0

0

0

0

0

0

0

0

G

0

0

1

1

1

1

1

1

1

1

1

1

1

T

0

0

1

1

2

2

2

2

2

2

2

2

2

T

0

0

1

1

2

2

2

3

3

3

3

3

3

C

0

0

1

1

2

2

2

3

3

3

3

3

3

C

0

1

1

1

2

2

2

3

3

3

3

3

3

T

0

1

1

1

2

2

2

4

4

4

4

4

4

A

0

1

1

2

2

3

3

3

4

4

5

5

5

A

0

1

1

2

2

3

4

4

4

4

5

5

6

T

0

1

1

2

3

3

4

5

5

5

5

5

6

A

0

1

1

2

3

4

4

5

5

5

6

6

6


红色数字的位置就揭示了最长公共子序列: CTATTA。也就是说分析这张表就可以得到最长公共子序列字符串。

 

为什么呢?因为通过表的回溯过程,从后向前重构了一个最长公共子序列。对于任何位置lcs[i][j],确定是否X[i]=Y[j]。如果是,那么X[i]必是最长公共子序列的一个字符。如果否,那么移动到lcs[i,j-1]和lcs[i-1, j]之间的较大者。


动态规划方法LCS效率:

 

动态规划方法构造最长公共子序列需要O(m*n)的代价,另外,如果想要得到最长公共子序列,又需要O(m+n)的时间来读取csl[][]数组。尽管如此,其时间复杂度仍然比蛮力穷举的指数级别要强的多。

 

 

 

问题拓展:设A,B,C是三个长为n的字符串,它们取自同一常数大小的字母表。设计一个找出三个串的最长公共子串的O(n^3)的时间算法。 (来自《Algorithm Design》(中文版:算法分析与设计) - Chapter9 - 文本处理 - 创新题C-9.18)

 

分析:可以通过《LCS 最长公共子序列 》的动态规划算法,设计Java源代码如下

public class TriLCS{
	
	char[] charA=null;
	char[] charB=null;
	char[] charC=null;
	
	
	public TriLCS(String sa,String sb,String sc){
		charA=new char[sa.length()+1];
		System.arraycopy(sa.toCharArray(),0,charA,1,sa.length());
		charB=new char[sb.length()+1];
		System.arraycopy(sb.toCharArray(),0,charB,1,sb.length());
		charC=new char[sc.length()+1];
		System.arraycopy(sc.toCharArray(),0,charC,1,sc.length());
	}
	
	public void getTriLCS(){
		
		int[][][] length=new int[charA.length][charB.length][charC.length];
		
		for(int a=1;a<charA.length;a++)
			for(int b=1;b<charB.length;b++)
				for(int c=1;c<charC.length;c++){
					
					if(charA[a]==charB[b]&&charA[a]==charC[c]){
						length[a][b][c]=length[a-1][b-1][c-1]+1;
					}
					else if(charA[a]==charB[b]&&charA[a]!=charC[c]){
						length[a][b][c]=max(length[a-1][b-1][c],length[a][b][c-1]);
					}
					else if(charA[a]==charC[c]&&charA[a]!=charB[b]){
						length[a][b][c]=max(length[a-1][b][c-1],length[a][b-1][c]);
					}
					else if(charB[b]==charC[c]&&charA[a]!=charB[b]){
						length[a][b][c]=max(length[a][b-1][c-1],length[a-1][b][c]);
					}
					else{
						length[a][b][c]=max(length[a-1][b][c],length[a][b-1][c],length[a][b][c-1],length[a-1][b-1][c],length[a-1][b][c-1],length[a][b-1][c-1]);
					}					
				}
		
		
		
		//打印最长公共子序列
		String lcstr="";	
		int a=charA.length-1;
		int b=charB.length-1;
		int c=charC.length-1;
		while(a>=1&&b>=1&&c>=1){
			if(charA[a]==charB[b]&&charA[a]==charC[c]){
				lcstr=charA[a]+lcstr;
				a--;
				b--;
				c--;
			}
			else if(charA[a]==charB[b]&&charA[a]!=charC[c]){
				if(length[a-1][b-1][c]<=length[a][b][c-1])
					c--;
				else{
					a--;
					b--;
				}
			}
			else if(charA[a]==charC[c]&&charA[a]!=charB[b]){
				if(length[a-1][b][c-1]<=length[a][b-1][c])
					b--;
				else{
					a--;
					c--;
				}
			}
			else if(charB[b]==charC[c]&&charA[a]!=charB[b]){
				if(length[a][b-1][c-1]<=length[a-1][b][c])
					a--;
				else{
					b--;
					c--;
				}
			}
			else{
				int maxize=max(length[a-1][b][c],length[a][b-1][c],length[a][b][c-1],length[a-1][b-1][c],length[a-1][b][c-1],length[a][b-1][c-1]);
				if(maxize==length[a-1][b][c])
					a--;
				if(maxize==length[a][b-1][c])
					b--;
				if(maxize==length[a][b][c-1])
					c--;
				if(maxize==length[a-1][b-1][c]){
					a--;
					b--;
				}
				if(maxize==length[a-1][b][c-1]){
					a--;
					c--;
				}
				if(maxize==length[a][b-1][c-1]){
					b--;
					c--;
				}	
			}
		}
		
		System.out.println("最长子串为:"+lcstr+"(length="+length[charA.length-1][charB.length-1][charC.length-1]+")");
	}
	
	/**
	 * 取最大值
	 */
	private int max(int m,int n){
		return m>n?m:n;
	}
	/**
	 * 取最大值
	 */
	private int max(int x,int y,int z,int k,int m,int n){
		int maxizen=0;
		if(maxizen<x) maxizen=x;
		if(maxizen<y) maxizen=y;
		if(maxizen<z) maxizen=z;
		if(maxizen<k) maxizen=k;
		if(maxizen<m) maxizen=m;
		if(maxizen<n) maxizen=n;
		return maxizen;
	}
	
	public static void main(String[] args){
		TriLCS tri=new TriLCS("aadsbbbcs","adsabcs","adbsbsdcs");
		tri.getTriLCS();
	}	
}


http://hxraid.iteye.com/blog/622462

http://blog.chinaunix.net/uid-26548237-id-3374211.html

http://blog.youkuaiyun.com/v_july_v/article/details/6695482


最长公共子序列(LCS问题) 先简单介绍下什么是最长公共子序列问题,其实问题很直白,假设两个序列X,Y,X的值是ACBDDCB,Y的值是BBDC,那么XY的最长公共子序列就是BDC。这里解决的问题就是需要一种算法可以快速的计算出这个最大的子序列,当然,用最简单的方法就是列出XY全部的子系列然后一个个对比,但这样的时间复杂度是绝对不能接受的。假设X的长度是m,Y的长度是n,拿X的一个子序列和Y进行对比的时间是n,计算X的全部子序 阅读详情

相关推荐

最长公共子序列——LCS(c/c++ 伪代码)

给定两个序列 X,Y,求X和Y的长度最长的公共子序列 背包二维,一维优化

THOOOR的博客 3635

【串和序列处理 6】LCS 最长公共子序列

LCS:又称 最长公共子序列。 其中子序列(subsequence)的概念不同于串的子串。它是一个不一定连续但按顺序取自字符串X中的字符序列。 例如:串"AAAG"就是串“CGATAATTGAGA”的一个子序列。     字符串的相似性问题可以通过求解两个串间的最长公共子序列(LCS)来得到。 当然如果使用穷举算法列出串的所有子序列,一共有2^n种,而每个子序列是否是另外一个...

ccnunlp的专栏 273

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

LCS问题描述 定义:最长公共子序列(Longest Common Subsequence),即定义两个序列X和Y,求X和Y的最长公共子序列(子序列:一个序列S任意删除若干个字符得到新序列T,则T叫做S的子序列) 例如:字符串13455与245576的最长公共子序列为455 LCS的意义:LCS可以描述两段文字之间的“相似度”,即它们的雷同程度,从而能够用来辨别抄袭。 LCS解法的探索...

bohenmian的博客 656

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

程序员编程艺术第十一章:最长公共子序列(LCS)问题 0、前言 程序员编程艺术系列重新开始创作了(前十章,请参考程序员编程艺术第一~十章集锦与总结)。回顾之前的前十章,有些代码是值得商榷的,因当时的代码只顾阐述算法的原理或思想,所以,很多的与代码规范相关的问题都未能做到完美。日后,会着力修善之。 搜遍网上,讲解这个LCS问题的文章不计其数,但...

dinongxu8804的博客 1538

Algorithm LCS最长公共子序列

算法: 递归法:对于序列A[0,n]]和B[0,m],LCS(A,B)无非三种情况 若A或B为空,则取作空序列,作为递归基 如果末字符相等,即A[n]=B[m]=‘X’,则取LCS(A[0,n),B[0,m))+‘X’,如果前者可以求解,则问题的规模被缩小 如果末字符不相等,即A[n]!=B[m],比如A[n]=a,B[m]=b,则a和b至多有一个会出现在最后的解里(对解有贡献)。因为...

A land whole of flowers. 304

AD9361快速锁定实战:Profile寄存器配置与频率调谐算法解析

本文深入解析了AD9361射频收发器的快速锁定(Fast Lock)功能,重点阐述了其核心机制——Profile寄存器配置。通过剖析16字节Profile结构,详细讲解了频率调谐算法,包括LO_DIV、LO_INT、LO_FRAC等关键参数的计算,以及如何通过查表获取优化的环路滤波器参数。文章提供了完整的Python算法示例和FPGA实现要点,旨在帮助工程师实现毫秒级甚至微秒级的频率切换,满足跳频通信等高性能应用需求。

weixin_29196315的博客 229

数据结构与算法(六):串

数据结构(六):串

weixin_62591732的博客 260

WhatsApp协议算法

我想其实有很多人还不太了WhatsApp群控,简单来说,它和我们常使用的微信聊天软件是类似的,只不过它是基于通讯录的,操作起来比较简单便捷,所以现在有很多国家都喜欢用WhatsApp。一般情况下,筛号不会造成账号被封的情况,但是呢,如果筛号的频率太快,就会被系统限制筛号能力,不再返回筛号结果,所以,筛号数量和速度一定要控制好。前天逛街突然灵光一现,为什么不试试多路访问呢,简单来说就是信道复用技术,马上跑回家,调取接口,接入通道,导入已经转换成协议的账号,成功登录!

2403_87755661的博客 1942

动态规划--公共子序列LCS

一、问题描述: 求两个字符串的最长公共子串的长度。两个字符串X和Z的公共子串是指X中按序取一些字符构成的子串与在Z中按同样方法得到的一个子串相同。 例如:X=“abcdefghi” Z=“xyazdwf” 则”a” “d” “f” “ad” “df” “adf”都是它们的公共子串,而最长公共子串的长度为3。 二、状态空间: f(i, j)表示第一个字符串

dream_three的博客 366

STM32 FOC半周期控制延时分析与硬件同步配置

在电机矢量控制(FOC)系统中,数字控制延时是影响电流环带宽、观测器收敛性与系统稳定性的核心瓶颈。其本质源于PWM更新、ADC采样与计算执行之间的时序错配,典型表现为1.5个PWM周期的相位滞后,导致滑模观测器(SMO)失效或高速振荡。通过零阶保持(ZOH)建模可量化该延时对系统相频特性的影响,并揭示其等效为0.5u(t)+0.5u(t−1)的平滑控制律。工程上突破的关键在于重构外设协同机制——以高级定时器重复计数器(RCR0)驱动中心对齐PWM的半周期更新事件,使控制量在0.5T_PWM内生效,同步触发多

flink9streamer的博客 1131

避坑指南:PyCINRAD处理CINRAD雷达数据时遇到的5个典型报错及解决方案

本文针对使用PyCINRAD库处理CINRAD雷达基数据时常见的5个典型报错,提供了详细的解决方案。内容涵盖环境配置、数据读取、PPI可视化及性能优化等核心环节,重点解决了版本兼容性、数据异常处理和中文乱码等实际问题,帮助用户高效处理雷达基数据并生成准确的PPI图像。

cc789的博客 1068

【算法】字符串中的子串与子序列

1.子串 定义: 子串指的是串中任意个连续的字符组成的子序列,称为该串的子串 举例: 假设字符串的长度为n,其非空子串的数目为你n(n+1)/2个。例如字符串“abc“的连续子串有 a,ab,abc,b,bc,c 代码:(实现求s字符串的所有不重复子串) //s为待求字符串,res集合为子串集合 void gets(string s, set<string> &res) { for (int i = 0; i < s.size(); i++) { for (int j = 1

qq_36553828的博客 9807

用Simulink对Carsim车辆进行档位控制

用Simulink对Carsim车辆进行档位控制一、carsim中的档位设置为开环控制二、在Constant目录下面选取一个选项并重新命名为constant :0 Gear三、双击进去设置常量为 0四、输入和输出IO通道五、验证 :输入 为 3 档 ----- 输出 为 3!六、参考 一、carsim中的档位设置为开环控制 二、在Constant目录下面选取一个选项并重新命名为constant :0 Gear 三、双击进去设置常量为 0 四、输入和输出IO通道 五、验证 :输入 为 3 档 -

qq_42027654的博客 2601

最长公共子序列(LCS)

区分子序列和子串子序列:给,也可以说从给定序列中选取几个元素的结果(有顺序)。子串:给定串中组成的子序列为该串的子串。举例: (最长公共子序列不唯一,但序列长度是相同的)

Zhang_Qin123的博客 3292

异构图中的注意力机制网络:节点级别和语义级别的注意力(Python实现)

在本文中,我们介绍了如何使用Python实现异构图中的节点级别注意力和语义级别注意力。通过语义级别注意力,我们可以根据节点的语义信息对节点进行加权聚合。在本文中,我们将介绍如何使用Python实现异构图中的注意力机制网络,包括节点级别的注意力和语义级别的注意力。最后,我们使用注意力权重对节点特征进行加权聚合,得到聚合后的节点表示。然后,将聚合后的节点表示传递给语义级别注意力模型,根据节点的语义信息进行加权聚合,得到最终的表示。函数中,首先使用节点级别注意力模型对节点特征进行聚合,得到聚合后的节点表示。

HackNebulaZ的博客 485

【Unity实战100例】Unity循环UI界面切换卡片功能

功能包括:可以设置半径,高度,速度,元素数量用户可以根据自己的实际需求接入 制作思路:创建每个元素对应的虚拟点,通过旋转管理这些虚拟点,然后把旋转信息和位置信息同步给实际的元素

纯技术流日常开发商业开发记录总结等 7717

最长公共子序列(LCS)

一、概念1.给定字符串str = "ABCDADNENXY"    子序列:从str中任意去掉若干个(含0个)字符,剩下的就是这个str的子序列,如ABC, ABXY, DADXY等,中间不必连续.    子串:和子序列不同,子串必须是连续的,如ABCD,ENXY,CDADNE都是子串,而AXY不是,因为中间断开了,把连续.    子串必定是子序列,子序列不一定是子串.2.最长公共子序列(Long...

tensory的博客 2万+

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

『经典DP入门』LCS 最长公共子序列问题

最长公共子序列问题(Longest Common Subsequence problem):给定两个序列X = <x1,x2,...,xm>和Y = <y1,y2,...,yn>,求X和Y长度最长的公共子序列。 注:本文的大多数概念及求解方法来自《算法导论》 使用动态规划求解LCS问题过程: 一、刻画最长公共子序列的特征 LCS的最优子结构定理:设X={x1,x2,...

Miserable_ccf的博客 7309

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

动态规划-求最长公共子序列LCS长度-输出所有的最长公共子序列LCS-Java实现

题目:给定两个序列X={x1,x2,…xm},Y={y1,y2,…yn},找出X和Y的最长公共子序列。 分析: 1 最长公共子序列概念 实现明确一个点就是,子序列是一个序列中去掉若干元素后得到的序列,也就是说子序列的元素下标是递增的就行,不需要在原序列中连续。 最长公共子序列,显而易见就是序列X和Y都有的最长的子序列。 2 BruteForce 暴力求解法 对于序列X的所有长度不超过Y的子序列,都...

天天开心 2729

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

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

问题描述:给定两个序列X=< x1,x2,x3,…,xm >和Y=< y1,y2,y3,…,yn >,求X和Y长度最长的公共子序列

努力努力再努力x 716

图解最长公共子序列LCS问题

很多人在上学的时候都有过对毕业论文进行查重的经历,一般可以通过CNKI,知网等平台提交自己的论文,平台将论文与其他论文进行匹配查重,最终得到一个相似度。不知大家对于查重问题有没有思考过,他背后是如何实现的呢?难道就是找到相似的字符串匹配就可以吗?本篇文章就带大家了解一种可以解决这个问题的经典算法。 本文主要主要包含以下三方面: 什么是LCS 如何实现LCS计算 LCS的使用场景 1. 什么是LCS 最长公共子序列,英文名称为Longest Commo...

Mike's Tech Blog 1935
上一篇: 几篇关于Amazon AWS的技术文章
下一篇: Inorder Successor in Binary Search Tree BST中找中序遍历的后继节点
chiiis
博客等级 码龄14年 422粉丝 429原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值