In computer science, the longest common substring problem is to find the longest string that is a substring of two or more strings.
Analysis
Given two strings a and b, let dp[i][j] be the length of the common substring ending at a[i] and b[j].
The dp table looks like the following given a=”abc” and b=”abcd”.
Java Solution
public static int getLongestCommonSubstring(String a, String b){ int m = a.length(); int n = b.length(); int max = 0; int[][] dp = new int[m][n]; for(int i=0; i<m; i++){ for(int j=0; j<n; j++){ if(a.charAt(i) == b.charAt(j)){ if(i==0 || j==0){ dp[i][j]=1; }else{ dp[i][j] = dp[i-1][j-1]+1; } if(max < dp[i][j]) max = dp[i][j]; } } } return max; } |
This is a similar problem like longest common subsequence. The difference of the solution is that for this problem when a[i]!=b[j], dp[i][j] are all zeros by default. However, in the longest common subsequence problem, dp[i][j] values are carried from the previous values, i.e., dp[i-1][j] and dp[i][j-1].
There are four different ways to solve this problem –
// Method1()- recursive solution(Top- down approach)
// time complexity - O(3^(m+n))
// space complexity - O(m+n)
public static int LCSubStrM1(char[] X, char[] Y, int m, int n, int lcsCount) {
if (m <= 0 || n <= 0)
return lcsCount;
int lcsCount1=lcsCount;
if (X[m - 1] == Y[n - 1])
lcsCount1 = LCSubStrM1(X, Y, m - 1, n - 1, lcsCount + 1);
int lcsCount2 = LCSubStrM1(X, Y, m, n - 1, 0);
int lcsCount3 = LCSubStrM1(X, Y, m - 1, n, 0);
return Math.max(lcsCount1, Math.max(lcsCount2, lcsCount3));
}
// Method2A1()- recursive solution with memoization (Top-down approach caching on method level)
public static int LCSubStrM2A1(char[] X, char[] Y, int m, int n, int lcsCount, Integer[][][] dp) {
if (m <= 0 || n <= 0)
return lcsCount;
if (dp[m][n][lcsCount] != null)
return dp[m][n][lcsCount];
int lcsCount1=lcsCount;
if (X[m - 1] == Y[n - 1])
lcsCount1 = LCSubStrM2A1(X, Y, m - 1, n - 1, lcsCount + 1, dp);
int lcsCount2 = LCSubStrM2A1(X, Y, m, n - 1, 0, dp);
int lcsCount3 = LCSubStrM2A1(X, Y, m - 1, n, 0, dp);
return dp[m][n][lcsCount] = Math.max(lcsCount1, Math.max(lcsCount2, lcsCount3));
}
// Method2A2()- recursive solution with memoization (Top-down approach caching on global level)
public static int LCSubStrM2A2(char[] X, char[] Y, int m, int n, int lcsCount) {
if (m <= 0 || n <= 0)
return lcsCount;
if (dp[m][n][lcsCount] != null)
return dp[m][n][lcsCount];
int lcsCount1=lcsCount;
if (X[m - 1] == Y[n - 1])
lcsCount1 = LCSubStrM2A2(X, Y, m - 1, n - 1, lcsCount + 1);
int lcsCount2 = LCSubStrM2A2(X, Y, m, n - 1, 0);
int lcsCount3 = LCSubStrM2A2(X, Y, m - 1, n, 0);
return dp[m][n][lcsCount] = Math.max(lcsCount1, Math.max(lcsCount2, lcsCount3));
}
// Method3()- DP solution(Bottom up approach)
// time complexity - O(m*n)
// space complexity - O(m*n)
public static int LCSubStrA3(char[] X, char[] Y, int m, int n) {
int memo[][] = new int[m + 1][n + 1];
int result = 0;
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (i == 0 || j == 0) {
memo[i][j] = 0;
} else if (X[i - 1] == Y[j - 1]) {
memo[i][j] = memo[i - 1][j - 1] + 1;
result = Math.max(result, memo[i][j]);
} else {
memo[i][j] = 0;
}
}
}
cache = memo;
return result;
}
for detailed explanation refer–https://www.youtube.com/watch?v=Lj90FqNCIJE&list=PLSIpQf0NbcClDpWE58Y-oSJro_W3LO8Nb
public static int substrLength(String str1, String str2){ //photograph,tomography
int count=0,mCount= 0;
for(int i=0;i<str1.length();i++){
for(int j=0;j<str2.length();j++){
if(str1.charAt(i)== str2.charAt(j)){
count =0;
for(int k=0;(k+i)<str1.length()&&(k+j)mCount)
mCount =count;
}
}
return mCount;
}