最长公共子序列问题

一个给定序列的子序列就是将给定子序列中零个或多个元素去掉之后得到的结果,即子序列要保持与原序列的相对顺序,不是一定要是原序列中连续的一块。正如最长公共子串和最长公共子序列的区别,前者要求是原序列中连续的一段。

给定序列X和Y,求解他们的最长公共子序列。最直接的方法就是暴力搜索的方法,穷举X的所有子序列,对每个子序列检查它是否也是Y的子序列,记录找到的最长子序列。因为X的每个子序列对应X的下标集合{1,2,3...m}的一个子集,所以X有2^m个子序列。所以运行时间是指数阶的,如果原序列较长的话比较不实用。另外一个最经典的方法就是动态规划...

     下面说下说下我理解的最长公共子序列求解步骤(来自算法导论)

 1.最长公共子序列(LCS)的最优子结构

                    

 2.递归解

根据1中的定理,在求X和Y的一个LCS时,我们需要求解一个或两个子问题。我们可以很容易的发现LCS问题的重叠子问题性质,为了求X和Y的一个LCS,我们可能需要求X和Y_{n-1}的一个LCS及X_{m-1}和Y的一个LCS。但是这几个子问题度包含求解X_{m-1}和Y_{n-1}的LCS的子子问题, 我们可以得到如下公式:


3.计算LCS的长度

      伪代码如下:

m=X.length
n=Y.length
let b[1..m,1..n]andc[0..m,0..m]be new tables
for i =1 to m
    c[i,0]=0
for j =0 to n
    c[0,j]=0
for i=1 to m
    for j=1 to n
	if Xi==Yi
		c[i,j]=c[i-1,j-1]+1
		b[i,j]="A" //其实就是代表指向左上角的箭头
	elseif c[i-1,j]>=c[i,j-1]
		c[i,j]=c[i-1,j]
		b[i,j]="B" //代表指向上方的箭头
	else 
		c[i,j]=c[i,j-1]
		b[i,j]="C" //代表指向左方的箭头
return c and b
c保存的是LCS的高度,b用于帮助构造最优解

4.构造LCS

PRINT_LCS(b,X,i,j)
	if i==0 or j==0
		return
	if b[i,j]=="A"
		PRINT_LCS(b,X,i-1,j-1)
	elseif b[i,j]=="B"
		PRINT_LCS(b,X,i-1,j)
	else
		PEINR_LCS(b,X,i,j-1)

下面是C++写的求解最长公共子序列长度代码

#include<iostream>
#include<string>

using namespace std;

int c[100][100];
int LCS_length(const char *X, const char *Y)
{
	if(X == NULL||Y == NULL)
		return 0;
	int m = strlen(X);
	int n = strlen(Y);
	for(int i=1;i<=m;i++)
		c[i][0]=0;
	for(int j=1;j<=n;j++)
		c[0][j]=0;
	c[0][0]=0;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
		{
			if(X[i] == Y[j])
				c[i][j]=c[i-1][j-1]+1;
			else
				c[i][j]=max(c[i-1][j],c[i][j-1]);
		}
	for(int i=1;i<=m;++i)
		{cout<<endl;
		for(int j=1;j<=n;++j)
			cout<<c[i][j]<<" ";
	}
	cout<<endl
	return c[m][n];
}

int main()
{
	char *a="ABCBDAB";
	char *b="BDCABA";
	int length;
	length = LCS_length(a,b);
	cout<<length<<endl;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值