数组X = [X0, X1, X2,... Xm]
子序列为 [Xi,Xj,Xk,...,Xz],其中,0<=i<j<k<...<z<=m
数组Y = [Y0, Y1, Y2,... Yn]
求X,Y的公共子序列中的最长的一个。
例子:
X = [A, B, C, B, D, A, B]
Y = [B, D, C, A, B, A]
[B, C, A]是X和Y的一个公共子序列,但不是最长公共子序列
[B, C, B, A]则是X和Y的最长公共子序列
(1) 最优子结构
设Z = [Z0, Z1, Z2, ..., Zk]是X和Y的最长子序列
如果 X[m] == Y[n],那么X[m]就是Z的最后一个,Z[0~k-1]则是X[0~m-1]和Y[0~n-1]的最长子序列。此为情况1.
否则 X[m] != Y[n],X[0~m]和Y[0~n-1]的最长子序列与 X[0~m-1]和Y[0~n]的最长子序列
二者之中较大的一个就是X和Y的最长子序列,分别为情况2和情况3
(2) 建立递归关系
以 Len(i, j) 表示 [X0, X1, X2,... Xi] 与 [Y0, Y1, Y2,... Yj] 的最长公共子序列的长度
* X[i] == Y[0] ? 1 : 0 i==0
* X[0] == Y[j] ? 1 : 0 j==0
* Len(i,j) = Len(i-1,j-1)+1 Xi==Yj
* max(Len(i-1,j), Len(i,j-1)) Xi!=Yj
(3)自底向上,计算各个子问题的最优解
分别从i=0,j=0开始计算Len(0, 0)至Len(m, n)
过程中,将backup[i][j]保存为三种情况中的一种,表示Len(i, j)这个最长子序列是从那种情况得来。
(4)求解整个问题的最优解
由backup[m][n]开始向前寻找前一个节点。
backup[i][j] == 1 : X[i]或y[j]都行
backup[i][j] == 2 : Len(i-1, j)比较大,故i--
backup[i][j] == 3 : Len(i, j-1)比较大,故j--
/**
* Longest Common Subsequence
* X = {X1,X2,X3,...,Xm}
* Y = {Y1,Y2,Y3,...,Yn}
* X[i] == Y[0] ? 1 : 0 i==0
* X[0] == Y[j] ? 1 : 0 j==0
* Len(i,j) = Len(i-1,j-1)+1 Xi==Yj
* max(Len(i-1,j), Len(i,j-1)) Xi!=Yj
* @author xuefeng
*
*/
public class LCS {
public static void lcs(int[] X, int[] Y) {
int m = X.length, n = Y.length;
int[][] len = new int[m][n];
int[][] backup = new int[m][n];
// 自底向上,计算各个子问题的最优解
for (int i = 0; i < m; i++)
if (X[i] == Y[0]) {
len[i][0] = 1;
backup[i][0] = 1;
} else {
len[i][0] = 0;
backup[i][0] = 0;
}
for (int j = 0; j < n; j++)
if (X[0] == Y[j]) {
len[0][j] = 1;
backup[0][j] = 1;
} else {
len[0][j] = 0;
backup[0][j] = 0;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (X[i] == Y[j]) {
backup[i][j] = 1;
len[i][j] = len[i - 1][j - 1] + 1;
} else {
if (len[i - 1][j] >= len[i][j - 1]) {
backup[i][j] = 2;
len[i][j] = len[i - 1][j];
} else {
backup[i][j] = 3;
len[i][j] = len[i][j - 1];
}
}
}
}
// 求解整个问题的最优解
LinkedList<Character> sequence = new LinkedList<Character>();
int i = m - 1, j = n - 1;
while (i >= 0 && j >= 0) {
if (backup[i][j] == 1) {
sequence.addFirst((char) X[i]);
i--;
j--;
} else if (backup[i][j] == 2) {
i--;
} else if (backup[i][j] == 3) {
j--;
} else {
break;
}
}
System.out.println(sequence);
}
public static void main(String[] args) {
int[] X = { 'A', 'B', 'C', 'B', 'D', 'A', 'B' };
int[] Y = { 'B', 'D', 'C', 'A', 'B', 'A' };
lcs(X, Y);
}
}