用动态规划的思想求解两个公共字符的X和Y最长公共子串:
c[i][j]表示Xi和Yj的LCS长度;b[i][j]表示对应计算c[i][j]时所选择的子问题最优解;
代表现在过程中,设置b中元素1表示书上的指向左上方的箭头,表示找到了xi=yj,c[i-1][j-1]+1;
当xi!=yj时,如果c[i-1][j]>=c[i][j-1],则b中元素2为指向向上的箭头;(备注:这里坐标轴为x竖直向下,y水平向右。)
当xi!=yj时,如果c[i-1][j]<c[i][j-1]表示c[i][j]=c[i-1][j];b中元素3为指向左边的箭头,表示c[i][j]=c[i][j-1];
public class LCS {
public static int c[][]; //c[i][j]表示Xi和Yj的LCS长度
public static int b[][]; //b[i][j]表示对应计算c[i][j]时所选择的子问题最优解
//代表现在过程中,设置b中元素1表示书上的指向左上方的箭头,表示找到了xi=yj
//b中元素2为指向向上的箭头,表示c[i][j]=c[i-1][j]
//b中元素3为指向左边的箭头,表示c[i][j]=c[i][j-1]
public static void lcsLength(char x[],char y[]){
int m=x.length;
int n=y.length;
c=new int[m][n];
b=new int[m][n];
for(int i=0;i<m;i++){
c[i][0]=0;
}
for(int j=0;j<n;j++){
c[0][j]=0;
}
for(int i=1;i<m;i++){ //确定了子问题的个数是O(m*n)
for(int j=1;j<n;j++){
if(x[i]==y[j]){
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
}
else{
if(c[i-1][j]>=c[i][j-1]){//
c[i][j]=c[i-1][j];
b[i][j]=2; //为2时表示此时 c[i][j]=c[i-1][j];
}else{
c[i][j]=c[i][j-1];
b[i][j]=3; //为3时表示此时 c[i][j]=c[i][j-1];
}
}
}
}
}
public static void printLcs(int b[][],char x[],int i,int j){//开始输出结果 初始时i j 分别是x和y的真实序列的长度
if(i==0||j==0){
return;
}
if(b[i][j]==1){
printLcs(b,x,i-1,j-1);
System.out.print(x[i]);
}else{
if(b[i][j]==2){
printLcs(b,x,i-1,j);
}else{
printLcs(b,x,i,j-1);
}
}
}
public static void main(String[] args){
//真实的X序列是ABCBDAB
//真实的Y序列是BDCABA
char[] x={' ','A','B','C','B','D','A','B'};//序列开始的第一个人为得添加为空格
char[] y={' ','B','D','C','A','B','A'};
LCS.lcsLength(x, y);
LCS.printLcs(b, x, x.length-1, y.length-1);
}
}