求两个字符串的最长公共子串长度
ABCBA 和 BABCA 的最长公共子串是 ABC,长度为 3
代码
static int Lcs(String str1,String str2) {
if(str1==null&&str2==null) return 0;
char[] char1=str1.toCharArray();
if(char1.length==0) return 0;
char[] char2=str2.toCharArray();
if(char2.length==0) return 0;
//dp[i][j]表示str1[i-1]和str2[j-1]结尾的最长公共子串长度
int[][] dp=new int[char1.length+1][char2.length+1];//+1才能让length作为下标dp[length+1-1]
int max=0;
for(int i=1;i<=char1.length;i++) {
for(int j=1;j<=char2.length;j++) {
if(char1[i-1]!=char2[j-1]) continue;
dp[i][j]=dp[i-1][j-1]+1;
max=Math.max(dp[i][j],max);
}
}
return max;
}
思路
设 dp(i, j) 是以 str1[i – 1]、str2[j – 1] 结尾的最长公共子串长度
dp(i, 0)、dp(0, j) 初始值均为 0
i ∈ [1, str1.length] ,j ∈ [1, str2.length] 为了保证dp数组i-1或j-1时取到两个字符串的第一个字符str1[0]或str2[0]
str1=ABCBA str2=BABCA
假设现在我们要求dp[1,1]即是求str1[0]A、str2[0]B 结尾的最长公共子串长度,str1[0不等str2[0],于是得到的是0,把0写入数组
假设现在我们要求dp[3,4]即是求str1[2]C、str2[3]C 结尾的最长公共子串长度,str1[2]=str2[3],于是与去找各自前面的一个字符,即dp[2,3],发现dp[2,3]求出来是2,于是得到2+1=3,最长公共子串长度是3。
上面的表格里的数是经过遍历存储在dp数组的里的
如果 str1[i – 1] = str2[j – 1],那么 dp(i, j) = dp(i – 1, j – 1) + 1
如果 str1[i – 1] ≠ str2[j – 1],那么 dp(i, j) = 0
最长公共子串的长度是所有 dp(i, j) 中的最大值 max { dp(i, j) }
一维数组实现
减少空间复杂度
static int Lcs2(String str1,String str2) {
if(str1==null&&str2==null) return 0;
char[] char1=str1.toCharArray();
if(char1.length==0) return 0;
char[] char2=str2.toCharArray();
if(char2.length==0) return 0;
char[] rowchar=char1;
char[] colchar=char2;
if(char1.length<char2.length) {
colchar=char1;
rowchar=char2;
}
int[] dp=new int[colchar.length+1];
int max=0;
for(int row=1;row<=rowchar.length;row++) {
int cur=0;
for(int col=1;col<=colchar.length;col++) {
int lefttop=cur;
cur=dp[col];
if(char1[row-1]!=char2[col-1]) {
dp[col]=0;
}else {
dp[col]=lefttop+1;
max=Math.max(dp[col],max);
}
}
}
return max;
}