给出两个字符串,找到最长公共子串,并返回其长度。
样例
样例 1:
输入: "ABCD" and "CBCE"
输出: 2
解释:
最长公共子串是 "BC"
样例 2:
输入: "ABCD" and "EACB"
输出: 1
解释:
最长公共子串是 'A' 或 'C' 或 'B'
挑战
O(n x m) time and memory.
注意事项
子串的字符应该连续的出现在原字符串中,这与子序列有所不同。
解题思路1:
暴力求解。时间复杂度O(N^3)
public class Solution {
/**
* @param A: A string
* @param B: A string
* @return: the length of the longest common substring.
*/
public int longestCommonSubstring(String A, String B) {
// write your code here
int res = 0;
char[] a = A.toCharArray();
char[] b = B.toCharArray();
for(int i = 0; i < a.length; i++){
for(int j = 0; j < b.length; j++){
int ii = i, jj = j;
int temp = 0;
while(ii < a.length && jj < b.length && a[ii] == b[jj]){
temp++;
ii++;
jj++;
}
res = Math.max(res, temp);
}
}
return res;
}
}
解题思路2:
类动态规划求解。时间复杂度O(N^2)
用例子来说明一切,ABCD 和ABDBCDF
这两个字符串的长度分别是4和7,我们建立一个4*7的二维数组,我们这里用行表示前面的ABCD,列表示后面的ABDBCDF:

然后,我们看每一条对角线:

我们先挑上面这条黄色的来演示一下:
先判断最上面那个格子,因为行列都是A,所以格子应该是1:

接下来,看对角线上的第二个格子也就是上面标红的格子:
因为行列都是B,所以这个格子等于它的左上方那个格子的数字加1,所以是2:

接下来继续看下一个格子,因为行是C,列是D,字符不相同,所以这个格子置零,看到这里我相信你应该知道怎么求解这个表格了,就不赘述了,直接看结果:

public class Solution {
/**
* @param A: A string
* @param B: A string
* @return: the length of the longest common substring.
*/
public int longestCommonSubstring(String A, String B) {
// write your code here
char[] a = A.toCharArray();
char[] b = B.toCharArray();
int res = 0;
if(a.length == 0 || b.length == 0)
return res;
//dp[i][j]表示A的前i个字符与B的前j个字符中,以第i个和第j个为结尾的公共子串的长度
int[][] dp = new int[a.length][b.length];
//边界条件
for(int i=0; i<a.length; i++)
if(a[i] == b[0]){
dp[i][0] = 1;
res = 1;
}
for(int j=0; j<b.length; j++)
if(b[j] == a[0]){
dp[0][j] = 1;
res = 1;
}
//递推式
for(int i=1; i<a.length; i++){
for(int j=1; j<b.length; j++){
if(a[i] == b[j]){
dp[i][j] = dp[i-1][j-1] + 1;
res = Math.max(res, dp[i][j]);
}
else
dp[i][j] = 0;
}
}
return res;
}
}
通过增加左上角一行与一列来避免边界条件的判断。
public class Solution {
/**
* @param A: A string
* @param B: A string
* @return: the length of the longest common substring.
*/
public int longestCommonSubstring(String A, String B) {
// write your code here
char[] a = A.toCharArray();
char[] b = B.toCharArray();
int res = 0;
if(a.length == 0 || b.length == 0)
return res;
//dp[i][j]表示A的前i个字符与B的前j个字符中,以第i个和第j个为结尾的公共子串的长度
int[][] dp = new int[a.length + 1][b.length + 1];
//递推式
for(int i=1; i<=a.length; i++){
for(int j=1; j<=b.length; j++){
if(a[i-1] == b[j-1]){
dp[i][j] = dp[i-1][j-1] + 1;
res = Math.max(res, dp[i][j]);
}
else
dp[i][j] = 0;
}
}
return res;
}
}

本文介绍两种求解最长公共子串的方法:暴力求解和动态规划。暴力求解的时间复杂度为O(N^3),而动态规划的时间复杂度为O(N^2)。通过实例详细解析动态规划的实现过程。
1318

被折叠的 条评论
为什么被折叠?



