举例:AOIDSAFKE和TGRARIDWQFKDA的最长公共子序列为AIDFK
设X=<x1,x2,x3,x4…,xm>,Y=<y1,y2,y3,y4…,yn>为两个序列,Z=<z1,z2,z3,z4…,zk>是他们的任意公共子序列
经过分析,我们可以知道:
1、如果xm = yn,则zk = xm = yn 且 Zk-1是Xm-1和Yn-1的一个LCS
2、如果xm != yn 且 zk != xm,则Z是Xm-1和Y的一个LCS
3、如果xm != yn 且 zk != yn,则Z是X和Yn-1的一个LCS
所以如果用一个二维数组c表示字符串X和Y中对应的前i,前j个字符的LCS的长度话,可以得到以下公式:
设
p1表示X的前 i-1 个字符和Y的前 j 个字符的LCS的长度
p2表示X的前 i 个字符和Y的前 j-1 个字符的LCS的长度
p表示X的前 i-1 个字符和Y的前 j-1 个字符的LCS的长度
p0表示X的前 i 个字符和Y的前 j 个字符的LCS的长度
如果X的第 i 个字符和Y的第 j 个字符相等,则p0 = p + 1
如果X的第 i 个字符和Y的第 j 个字符不相等,则p0 = max(p1,p2)
在对应字符相等的时候,用↖标记
在p1 >= p2的时候,用↑标记
在p1 < p2的时候,用←标记
代码:
public class LCSLength {
static String path; //最长公共子序列
public static void main(String[] args) {
String x = "AOIDSAFKE";
String y = "TGRARIDWQFKDA";
int[][] matrix = new int[x.length()+1][y.length()+1];
int[][] direction = new int[x.length()+1][y.length()+1]; //0表示左上箭头,1表示上箭头,-1表示左箭头
for (int i = 1; i < matrix.length; i++) {
for (int j = 1; j < matrix[0].length; j++) {
if(x.charAt(i-1)==y.charAt(j-1)){
matrix[i][j] = matrix[i-1][j-1]+1;
direction[i][j] = 0;
}else{
if(matrix[i][j-1]>=matrix[i-1][j]){
matrix[i][j] = matrix[i][j-1];
direction[i][j] = -1;
}else{
matrix[i][j] = matrix[i-1][j];
direction[i][j] = 0;
}
}
}
}
// for (int i = 0; i < matrix.length; i++) {
// for (int j = 0; j < matrix[0].length; j++) {
// System.out.print(direction[i][j]+"\t");
// }
// System.out.println();
// }
printPath(y,direction,x.length()-1,y.length()-1);
System.out.println(path);
}
private static void printPath(String y,int[][] direction,int i,int j) { //根据direction找最长公共子序列
if(i>=1&&j>=1){
if(direction[i][j] == 0){
if(path == null){
path = String.valueOf(y.charAt(j-1));
}else{
path = String.valueOf(y.charAt(j-1))+path;
}
printPath(y,direction,i-1,j-1);
}else if(direction[i][j] == 1){
printPath(y,direction,i-1,j);
}else{
printPath(y,direction,i,j-1);
}
}else{
return;
}
}
}