最长公共子序列

最长公共子序列的动态规划法实现最长公共子序列(longest-common-subsequence, LCS)
(1)子序列:一个序列X = x1x2…xn,中任意删除若干项,剩余的序列叫做A的一个子序列。也可以认为是从序列A按原顺序保留任意若干项得到的序列。
例如:对序列 1,3,5,4,2,6,8,7来说,序列3,4,8,7 是它的一个子序列。对于一个长度为n的序列,它一共有2^n 个子序列,有(2^n – 1)个非空子序列。在这里需要提醒大家,子序列不是子集,它和原始序列的元素顺序是相关的。
(2)公共子序列:如果序列Z既是序列X的子序列,同时也是序列Y的子序列,则称它为序列X和序列Y的公共子序列。空序列是任何两个序列的公共子序列。
(3)最长公共子序列:X和Y的公共子序列中长度最长的(包含元素最多的)叫做X和Y的最长公共子序列。
这个问题如果用穷举法时间,最终求出最长公共子序列时,时间复杂度是Ο(2mn),是指数级别的复杂度,对于长序列是不适用的。因此我们使用动态规划法来求解。刻画最长公共子序列问题的最优子结构
设X=x1x2…xm和Y=y1y2…yn是两个序列,Z=z1z2…zk是这两个序列的一个最长公共子序列。

  1. 如果xm=yn,那么zk=xm=yn,且Zk-1是Xm-1,Yn-1的一个最长公共子序列;      
    
  2. 如果xm≠yn,那么zk≠xm,意味着Z是Xm-1,Y的一个最长公共子序列;      
    
  3. 如果xm≠yn,那么zk≠yn,意味着Z是X,Yn-1的一个最长公共子序列。     
    

从上面三种情况可以看出,两个序列的LCS包含两个序列的前缀的LCS。因此,LCS问题具有最优子结构特征。
递归的定义最优值
从最优子结构可以看出,如果xm=yn,那么我们应该求解Xm-1,Yn-1的一个LCS,并且将xm=yn加入到这个LCS的末尾,这样得到的一个新的LCS就是所求。
如果xm≠yn,我们需要求解两个子问题,分别求Xm-1,Y的一个LCS和X,Yn-1的一个LCS。两个LCS中较长者就是X和Y的一个LCS。
可以看出LCS问题具有重叠子问题性质。为了求X和Y的一个LCS,我们需要分别求出Xm-1,Y的一个LCS和X,Yn-1的一个LCS,这几个字问题又包含了求出Xm-1,Yn-1的一个LCS的子子问题。
根据上面的分析,我们可以得出下面的公式;

#include<iostream>
#include<algorithm>
using namespace std;
char stra[1000] = "fish";
char strb[1000] = "fosh";
int alen, blen;
int maxlen[1000][1000];
int main(void){
	alen = strlen(stra);
	blen = strlen(strb);
	for (int i = 0; i <= alen; i++)
		maxlen[i][0] = 0;
	for (int j = 0; j <= alen; j++)
		maxlen[0][j] = 0;
	for (int i = 1; i <= alen; i++){
		for (int j = 1; j <= blen; j++){
			if (stra[i - 1] == strb[j - 1]){
/*1、xm=yn,那么zk=xm=yn,且Zk-1是Xm-1,Yn-1的一个最长公共子序列*/
				maxlen[i][j] = maxlen[i - 1][j - 1] + 1;
			}
			else
/*2、如果xm≠yn,那么zk≠xm,意味着Z是Xm-1,Y的一个最长公共子序列      
3、如果xm≠yn,那么zk≠yn,意味着Z是X,Yn-1的一个最长公共子序列*/
				maxlen[i][j] = max(maxlen[i][j - 1], maxlen[i - 1][j]);
			cout << maxlen[i][j] << " ";
		}
		cout << endl;	
	}	
	cout << maxlen[alen][blen];
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值