最大公共子序列

文章目录

  • 一、==最长公共子序列==(LCS)是什么?
  • 二、如何解决?
    • 1.分析问题
    • 2.递推公式
    • 3.构造最优解


一、最长公共子序列(LCS)是什么?

看一个例子:S1={1,5,2,8,9,3,6},S2={5,6,8,9,3,7},其最长公共子序列为{5,8,9,3}。

注意:最长公共子串和最长公共子序列是不同的。顾名思义,前者必须是连续的,后者只要求顺序一样即可。

二、如何解决?

1.分析问题

设序列S1={x1,x2,…,xn} 和 S2={y1,y2,…,ym} 的最长公共子序列为 S={z1,z2,…,zk}。
我们首先分析两个序列 S1,S2 的最后一个元素 xn, ym。

1)若 xn = ym,则这俩元素都一定属于序列S,即 xn = ym = zk;

2)若xn ≠ ym,且 zk ≠ xn,则 S[k] 是 S1[n-1] 和 S2[m] 的最长公共子序列;

3)若xn ≠ ym,且 zk ≠ ym,则 S[k] 是 S1[n] 和 S2[m-1] 的最长公共子序列;

2.递推公式

最大公共子序列_第1张图片
根据dp[][]间的对应位置关系,存储到 b 数组中,详见代码:

最大公共子序列_第2张图片

for(int i=1;i<=n;i++) c[i][0]=0;
for(int j=1;j<=m;j++) c[0][j]=0;

for(int i=1;i<=n;i++){
	for(int j=1;j<=m;j++){
		if(S1[i]==S2[j]){xiexiangshangjiantou
			dp[i][j]=dp[i-1][j-1]+1;
			b[i][j]=1;	//1代表“↖”			
		}
		else if(dp[i-1][j]>dp[i][j-1]){
			dp[i][j]=dp[i-1][j];
			b[i][j]=2; //2代表“↑”		
		}
		else{
			dp[i][j]=dp[i][j-1];
			b[i][j]=3; //3代表“←”		
		}
	}
}

下图为求解最大公共子序列 S 长度的图解
最大公共子序列_第3张图片

3.构造最优解

void LSC(int i,int j){
	if(i==0||j=0)
		return;
	if(b[i][j]==1){
		LCS(i-1,j-1);
		cout<<S1[i]<<" ";
	}
	else if(b[i][j]==2)
		LSC(i-1,j);
	else
		LSC(i,j-1);
}

下图为数组 b 的图解
最大公共子序列_第4张图片
右下角开始,值为3时“←”,值为2时“↑”,值为1时“↖”,这样就找到了路径。返回时,如果 b[i][j]为1就输出。于是得到{5,8,9,3}。
最大公共子序列_第5张图片

你可能感兴趣的:(最大公共子序列)