1.问题描述:求两个字符数组的最长公共子序列,子序列可以是不连续的,也就是一个长度为n的字符数组可以有
2n
个子序列。
2.数学分析:设字符数组
A[a1,a2,a3...,am],B[b1,b2,b3...bn]
如果
am
=
bn
,那么最长公共子序列的长度为
[a1,a2,a3...,am−1]和[b1,b2,b3...bn−1]
的最长公共子序列加1,如果
am!=bn
,那么最长公共子序列的长度就应该在
[a1,a2,a3...,am]、[b1,b2,b3...bn−1]
和
[a1,a2,a3...,am−1]、[b1,b2,b3...bn]
的最长公共子序列长度中取最大值。
那么设二维数组C[m][n]来记录A、B所有子序列的公共子序列长度,然后再通过回溯来得到公共子序列。有公式:
C[i][j]=⎧⎩⎨0C[m−1][n−1]+1max{C[m−1][n],C[m][n−1]}i=0orj=0,ai=bj,ai!=bj,
3.实现代码:
public class LCS{
static String[] a = { "B", "D", "C", "A", "B", "A" };
static String[] b = { "A", "B", "C", "B", "D", "A", "B" };
static int[][] c = new int[a.length + 1][b.length + 1];
static Stack<String> s = new Stack<String>();
public static void main(String args[]){
for(int i = 1, j = a.length; i <= j; i++){
for(int k = 1, l = b.length; k <= l; k++){
if(a[i-1].equals(b[k-1]))
c[i][k] = c[i-1][k-1] + 1;
else
c[i][k] = (c[i][k-1] > c[i-1][k]) ? c[i][k-1] : c[i-1][k];
}
}
}
//打印LCS,但是只能打印出一条LCS,打印全部LCS有空再补上
private static void printLcs(int ai, int bi){
if(ai == 0 || bi ==0)
return;
else if(a[ai-1].equals(b[bi-1])){
System.out.print(a[ai-1]);
printLcs(ai-1, bi-1);
}
else if(c[ai][bi-1] == c[ai][bi])
printLcs(ai, bi-1);
else
printLcs(ai-1, bi);
}
}