1.定义
最长公共子序列LCS(Longest Common Subsequence):一个数列 ,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 称为已知序列的最长公共子序列。
如:str1=“hfauag”,str2="afhuawg",最长公共子序列为:“huag”
2.应用
判断两段文字的相似性,用于判别文章是否抄袭。
3.算法原理和步骤:
假设两个序列:x={x1,...,xm},y={y1,...,yn} 的最长公共子序列为 z={z1,z2,...,zk}
① 若xm=yn,则zk=xm=yn,因此:{x1,...,xm-1},{y1,...,yn-1}的最长公共子序列为 {z1,...,zk-1}
② 若xm!=yn,则若xm!=zk,意味着:{x1,...,xm-1},{y1,...,yn}的最长公共子序列为 {z1,...,zk}
即:求{x1,...,xm},{y1,...,yn} 的LCS等同于:求{x1,...,xm-1},{y1,...,yn}的LCS
③ 若xm!=yn,则若ym!=zk,意味着:{x1,...,xm},{y1,...,yn-1}的最长公共子序列为 {z1,...,zk}
即:求{x1,...,xm},{y1,...,yn} 的LCS等同于:求{x1,...,xm},{y1,...,yn-1}的LCS
因此,用一个数组C保存LCS的长度,递推关系生成:
4.代码:
public class Main {
public static int[][] LCS(String str1,String str2){
/*
* 输入:序列str1,str2
*/
int[][] C=new int[str2.length()+1][str1.length()+1];
for(int i=0;i<=str2.length();++i){ //边界置零
C[i][0]=0;
}
for(int i=0;i<=str1.length();++i){ //边界置零
C[0][i]=0;
}
for(int i=1;i<=str2.length();++i){
for(int j=1;j<=str1.length();++j){
if(str1.charAt(j-1)==str2.charAt(i-1))
C[i][j]=C[i-1][j-1]+1;
else
{
if(C[i][j-1]>C[i][j-1])
C[i][j]=C[i][j-1];
else
C[i][j]=C[i-1][j];
}
}
}
return C; //返回长度矩阵
}
//递归打印输出LCS(逆向)
public static void printLCS(int[][] C,String str1,String str2,int i,int j) {
if(i==0 || j==0)
return;
if(str1.charAt(i-1)==str2.charAt(j-1)){
System.out.println(str1.charAt(i-1));
printLCS(C, str1, str2, i-1, j-1);
}
else{
if(C[i-1][j]>C[i][j-1])
printLCS(C, str1, str2, i-1, j);
else
printLCS(C, str1, str2, i, j-1);
}
}
public static void main(String[] args) {
String str1="afhuawg"; //测试用例
String str2="hfauag";
int [][] C=LCS(str1, str2);
printLCS(C, str1, str2, str1.length(), str2.length());
}
}