子序列
X=(A,B,C,B,D,B)
Z=(B,C,D,B)是X的子序例
W=(B,D,A)不是X的子序例
公共子序列
Z是序列X与Y的公共子序列如果Z是X的子序 也是Y的子序列。
最长公共子序列(LCS)问题
输入:X = (x1,x2,...,xn),Y = (y1,y2,...ym)
输出:Z = X与Y的最长公共子序列
蛮力法
枚举X的每个子序列Z
检查Z是否为Y的子序列
T(n)=O(m)
-----------------------------------------------------分界线,下面开始介绍动态规划求解算法-------------------------------------------------------
第i前缀:
设X=(x1,x2, ..., x n)是一个序列,X的第i前缀Xi 是一个序列,定义为Xi=(x1,...,xi)
例. X=(A, B, D, C, A), X1=(A), X2=(A, B), X3=(A, B, D)
优化子结构
算法结构
算法SimpleLCS(X,Y)
输入:X = (x1,x2,...,xn),Y = (y1,y2,...ym)
输出:X,Y的最长公共子序列
1. If m=0 或 n=0 Then 输出空串,算法结束;
2. If xn=ym Then
3. 输出SimpleLCS(Xn-1,Ym-1)+<xn>;
4. Else
5. Z1=SimpleLCS(Xn-1,Y);
6. Z2=SimpleLCS(X,Ym-1);
7. 输出Z1,Z2中较长者;
分析可得子问题具有重叠性
上图理解:知道下层所有子序列,就可以推断出上层子序列
LCS长度的递归方程
(C[i, j] = Xi与Yj 的LCS的长度 )
C[i, j] = 0 if i=0 或j=0
C[i, j] = C[i-1, j-1] + 1 if i, j>0 and xi = yj
C[i, j] = Max(C[i, j-1], C[i-1, j]) if i, j>0 and xi yj
基本思想
知道上图中蓝色的三项,通过对第i,j号元素的比较就可以求出C[i,j]
计算过程
上图中第一行和第一列的元素可以通过两序列率先求得,然后依照上面公式顺序求出各行的长度
伪代码
Java实现
public class LCS {
public static void main(String[] args) {
char[] a= {'a','b','v','s','g','s','f'};
char[] b= {'a','v','g','s','g','s'};
getLCS(a, b);
}
public static char[] getLCS(char[] a,char[] b) {
int m=a.length,n=b.length;
char[] result0 = {};
if(m==0||n==0) {
return result0;
}
int [][] c=new int[m][n];
int [][] direction=new int[m][n];
//初始化第一行
int i=0;
while(a[0]!=b[i]&&i<=n) {
c[0][i]=0;
i++;
}
for (int j=i;j<n;j++) {
c[0][j]=1;
}
//初始化第一列
i=0;
while(b[0]!=a[i]&&i<=m) {
c[i][0]=0;
i++;
}
for (int j=i;j<m;j++) {
c[j][0]=1;
}
for(i=1;i<m;i++) {
for(int j=1;j<n;j++) {
if(a[i]==b[j]) {
c[i][j]=c[i-1][j-1]+1;
direction[i][j]=0;//表示指向左上方
}else if(c[i-1][j]>c[i][j-1]){
c[i][j]=c[i-1][j];
direction[i][j]=1;//表示指向上方
}else {
c[i][j]=c[i][j-1];//表示指向左方
}
}
}
for(i=0;i<m;i++) {
for(int j=0;j<n;j++) {
System.out.print(c[i][j]+" ");
}
System.out.println();
}
System.out.println("----------------------------");
printLCS(a, direction, m, n);
return null;
}
public static void printLCS(char[] a ,int[][] direction,int m,int n) {
if(m==0||n==0) {
return;
}
if(direction[m-1][n-1]==0){
System.out.println(a[m-1]);
printLCS(a, direction, m-1, n-1);
}
if(direction[m-1][n-1]==1) {
printLCS(a, direction, m-1, n);
}
if(direction[m-1][n-1]==-1) {
printLCS(a, direction, m, n-1);
}
}
}