两个字符串的最长公共子序列(max common sequence)
九度OJ链接:http://ac.jobdu.com/problem.php?pid=1042
两个字符串的最长公共子序列是指给定两个字符串,找出这两个字符串中相同的字符的序列,这些字符不要求连续(注意与最长公共子串的区别,最长公共子串要求字符是连续的)
举个例子,比如字符串 X: "FABCDF" , Y: "ABFDE"
X和Y的最长公共子序列长度为 3,即 "ABD",注意"AB"和"D"并没有连续。
X和Y的最长公共子串的长度为2,即"AB"
假设 L(Xi,Yj) 表示X字符串从0-i的子串与Y字符串从0-j的子串的最长公共子序列长度,CX[i]表示字符串X在索引为i处的字符,CY[j]表示字符串Y在索引为j处的字符,则有(状态转移方程):
L(Xi,Yj)=L(X(i-1),Y(j-1))+1, 如果CX[i]==CY[j];
L(Xi,Yj)=max( L(X(i-1),Yj) , L(Xi,Y(j-1)) ), 如果CX[i]!=CY[j]
就上面的例子来看,由于CX[5]='F', CY[4]='E',即CX[5]!=CY[4],因此L(X5,Y4)=max( L(X4,Y4) , L(X5,Y3) ),即字符串"FABCDF"与"ABFD"的最大公共子序列与字符串"FABCD"与"ABFDE"的最大公共子序列二者的较大者
递归代码:
public int maxCommomSubSequence(String s1,String s2){
if(s1.length()<=0 || s2.length()<=0)
return 0;
if(s1.length()==1 &&s2.length()==1){
return s1.charAt(0)==s2.charAt(0)?1:0;
}
if(s1.charAt(s1.length()-1)==s2.charAt(s2.length()-1)){
return 1+maxCommomSubSequence(s1.substring(0, s1.length()-1),s2.substring(0,s2.length()-1));
}else
return Math.max(maxCommomSubSequence(s1.substring(0, s1.length()-1),s2.substring(0,s2.length())),
maxCommomSubSequence(s1.substring(0, s1.length()),s2.substring(0,s2.length()-1)));
}
public int maxCommomSubSequence2(String s1,String s2){
//用于保存Xi Yj 两个字符串的最大公共子序列长度
int[][] commonSubSqsLen=new int[s1.length()][s2.length()];
int maxLen=0;//表示两个字符串的最大公共子序列长度
for(int i=0;i=0&&j-1>=0){
commonSubSqsLen[i][j]=1+commonSubSqsLen[i-1][j-1];
}else{
commonSubSqsLen[i][j]=1;
}
}else{
if(i-1>=0){
if(j-1>=0){
commonSubSqsLen[i][j]=Math.max(commonSubSqsLen[i][j-1],commonSubSqsLen[i-1][j]);
}else{
commonSubSqsLen[i][j]=commonSubSqsLen[i-1][j];
}
}else{
if(j-1>=0){
commonSubSqsLen[i][j]=commonSubSqsLen[i][j-1];
}else{
commonSubSqsLen[i][j]=0;
}
}
}
if(commonSubSqsLen[i][j]>maxLen)
maxLen=commonSubSqsLen[i][j];
}
}
for(int i=0;i
以上面这个例子,输出结果为:
[0, 0, 1, 1, 1]
[1, 1, 1, 1, 1]
[1, 2, 2, 2, 2]
[1, 2, 2, 2, 2]
[1, 2, 2, 3, 3]
[1, 2, 3, 3, 3]
3
1. 求出两个字符串的所有最大公共子序列?
2. 求两个字符串的最大公共子串?