Longest Common Substring | DP-29
Last Updated :
27 Dec, 2023
Given two strings ‘X’ and ‘Y’, find the length of the longest common substring.Â
Examples :Â
Input : X = “GeeksforGeeks”, y = “GeeksQuiz”Â
Output : 5Â
Explanation:
The longest common substring is “Geeks” and is of length 5.
Input : X = “abcdxyz”, y = “xyzabcd”Â
Output : 4Â
Explanation:
The longest common substring is “abcd” and is of length 4.
Input : X = “zxabcdezy”, y = “yzabcdezx”Â
Output : 6Â
Explanation:
The longest common substring is “abcdez” and is of length 6.
Approach:
Let m and n be the lengths of the first and second strings respectively.
A simple solution is to one by one consider all substrings of the first string and for every substring check if it is a substring in the second string. Keep track of the maximum length substring. There will be O(m^2) substrings and we can find whether a string is substring on another string in O(n) time (See this). So overall time complexity of this method would be O(n * m2)
Dynamic Programming can be used to find the longest common substring in O(m*n) time. The idea is to find the length of the longest common suffix for all substrings of both strings and store these lengths in a table.Â
The longest common suffix has following optimal substructure property.Â
If last characters match, then we reduce both lengths by 1Â
- LCSuff(X, Y, m, n) = LCSuff(X, Y, m-1, n-1) + 1 if X[m-1] = Y[n-1]Â
If last characters do not match, then result is 0, i.e.,Â
- LCSuff(X, Y, m, n) = 0 if (X[m-1] != Y[n-1])
Now we consider suffixes of different substrings ending at different indexes.Â
The maximum length Longest Common Suffix is the longest common substring.Â
LCSubStr(X, Y, m, n) = Max(LCSuff(X, Y, i, j)) where 1 <= i <= m and 1 <= j <= nÂ
Following is the iterative implementation of the above solution. Â
C++
#include <iostream>
#include <string.h>
using namespace std;
int LCSubStr( char * X, char * Y, int m, int n)
{
int LCSuff[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)
LCSuff[i][j] = 0;
else if (X[i - 1] == Y[j - 1]) {
LCSuff[i][j] = LCSuff[i - 1][j - 1] + 1;
result = max(result, LCSuff[i][j]);
}
else
LCSuff[i][j] = 0;
}
}
return result;
}
int main()
{
char X[] = "OldSite:GeeksforGeeks.org" ;
char Y[] = "NewSite:GeeksQuiz.com" ;
int m = strlen (X);
int n = strlen (Y);
cout << "Length of Longest Common Substring is "
<< LCSubStr(X, Y, m, n);
return 0;
}
|
Java
import java.io.*;
class GFG {
static int LCSubStr( char X[], char Y[], int m, int n)
{
int LCStuff[][] = 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 )
LCStuff[i][j] = 0 ;
else if (X[i - 1 ] == Y[j - 1 ]) {
LCStuff[i][j]
= LCStuff[i - 1 ][j - 1 ] + 1 ;
result = Integer.max(result,
LCStuff[i][j]);
}
else
LCStuff[i][j] = 0 ;
}
}
return result;
}
public static void main(String[] args)
{
String X = "OldSite:GeeksforGeeks.org" ;
String Y = "NewSite:GeeksQuiz.com" ;
int m = X.length();
int n = Y.length();
System.out.println(
"Length of Longest Common Substring is "
+ LCSubStr(X.toCharArray(), Y.toCharArray(), m,
n));
}
}
|
Python3
def LCSubStr(X, Y, m, n):
LCSuff = [[ 0 for k in range (n + 1 )] for l in range (m + 1 )]
result = 0
for i in range (m + 1 ):
for j in range (n + 1 ):
if (i = = 0 or j = = 0 ):
LCSuff[i][j] = 0
elif (X[i - 1 ] = = Y[j - 1 ]):
LCSuff[i][j] = LCSuff[i - 1 ][j - 1 ] + 1
result = max (result, LCSuff[i][j])
else :
LCSuff[i][j] = 0
return result
X = 'OldSite:GeeksforGeeks.org'
Y = 'NewSite:GeeksQuiz.com'
m = len (X)
n = len (Y)
print ( 'Length of Longest Common Substring is' ,
LCSubStr(X, Y, m, n))
|
C#
using System;
class GFG {
static int LCSubStr( string X, string Y, int m, int n)
{
int [, ] LCStuff = 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)
LCStuff[i, j] = 0;
else if (X[i - 1] == Y[j - 1])
{
LCStuff[i, j]
= LCStuff[i - 1, j - 1] + 1;
result
= Math.Max(result, LCStuff[i, j]);
}
else
LCStuff[i, j] = 0;
}
}
return result;
}
public static void Main()
{
String X = "OldSite:GeeksforGeeks.org" ;
String Y = "NewSite:GeeksQuiz.com" ;
int m = X.Length;
int n = Y.Length;
Console.Write( "Length of Longest Common"
+ " Substring is "
+ LCSubStr(X, Y, m, n));
}
}
|
Javascript
<script>
function LCSubStr( X, Y , m , n) {
var LCStuff =
Array(m + 1).fill().map(()=>Array(n + 1).fill(0));
var result = 0;
for (i = 0; i <= m; i++) {
for (j = 0; j <= n; j++) {
if (i == 0 || j == 0)
LCStuff[i][j] = 0;
else if (X[i - 1] == Y[j - 1]) {
LCStuff[i][j] = LCStuff[i - 1][j - 1] + 1;
result = Math.max(result, LCStuff[i][j]);
} else
LCStuff[i][j] = 0;
}
}
return result;
}
var X = "OldSite:GeeksforGeeks.org" ;
var Y = "NewSite:GeeksQuiz.com" ;
var m = X.length;
var n = Y.length;
document.write( "Length of Longest Common Substring is " +
LCSubStr(X, Y, m, n));
</script>
|
PHP
<?php
function LCSubStr( $X , $Y , $m , $n )
{
$LCSuff = array_fill (0, $m + 1,
array_fill (0, $n + 1, NULL));
$result = 0;
for ( $i = 0; $i <= $m ; $i ++)
{
for ( $j = 0; $j <= $n ; $j ++)
{
if ( $i == 0 || $j == 0)
$LCSuff [ $i ][ $j ] = 0;
else if ( $X [ $i - 1] == $Y [ $j - 1])
{
$LCSuff [ $i ][ $j ] = $LCSuff [ $i - 1][ $j - 1] + 1;
$result = max( $result ,
$LCSuff [ $i ][ $j ]);
}
else $LCSuff [ $i ][ $j ] = 0;
}
}
return $result ;
}
$X = "OldSite:GeeksforGeeks.org" ;
$Y = "NewSite:GeeksQuiz.com" ;
$m = strlen ( $X );
$n = strlen ( $Y );
echo "Length of Longest Common Substring is " .
LCSubStr( $X , $Y , $m , $n );
?>
|
Output
Length of Longest Common Substring is 10
Time Complexity: O(m*n)Â
Auxiliary Space: O(m*n), since m*n extra space has been taken.
Another Approach: (Space optimized approach).
In the above approach, we are only using the last row of the 2-D array only, hence we can optimize the space by usingÂ
a 2-D array of dimension 2*(min(n,m)).
Below is the implementation of the above approach:
C++
#include <iostream>
#include <vector>
using namespace std;
int LCSubStr(string s, string t, int n, int m)
{
vector<vector< int >> dp(n + 1, vector< int >(m + 1, 0));
int res = 0;
for ( int i = 1; i <= n; i++)
{
for ( int j = 1; j <= m; j++)
{
if (s[i - 1] == t[j - 1])
{
dp[i][j] = dp[i - 1][j - 1] + 1;
if (dp[i][j] > res)
res = dp[i][j];
}
else
dp[i][j] = 0;
}
}
return res;
}
int main()
{
string X = "dddabcaafdgssfdgsdg" ;
string Y = "bbbabcdeffffffff" ;
int m = X.length();
int n = Y.length();
cout << LCSubStr(X, Y, m, n);
return 0;
}
|
Java
import java.io.*;
class GFG
{
static int LCSubStr(String s,String t,
int n, int m)
{
int dp[][]= new int [ 2 ][m+ 1 ];
int res= 0 ;
for ( int i= 1 ;i<=n;i++)
{
for ( int j= 1 ;j<=m;j++)
{
if (s.charAt(i- 1 )==t.charAt(j- 1 ))
{
dp[i% 2 ][j]=dp[(i- 1 )% 2 ][j- 1 ]+ 1 ;
if (dp[i% 2 ][j]>res)
res=dp[i% 2 ][j];
}
else dp[i% 2 ][j]= 0 ;
}
}
return res;
}
public static void main (String[] args)
{
String X= "OldSite:GeeksforGeeks.org" ;
String Y= "NewSite:GeeksQuiz.com" ;
int m=X.length();
int n=Y.length();
System.out.println(LCSubStr(X,Y,m,n));
}
}
|
Python3
def LCSubStr(s, t, n, m):
dp = [[ 0 for i in range (m + 1 )] for j in range ( 2 )]
res = 0
for i in range ( 1 ,n + 1 ):
for j in range ( 1 ,m + 1 ):
if (s[i - 1 ] = = t[j - 1 ]):
dp[i % 2 ][j] = dp[(i - 1 ) % 2 ][j - 1 ] + 1
if (dp[i % 2 ][j] > res):
res = dp[i % 2 ][j]
else :
dp[i % 2 ][j] = 0
return res
X = "OldSite:GeeksforGeeks.org"
Y = "NewSite:GeeksQuiz.com"
m = len (X)
n = len (Y)
print (LCSubStr(X,Y,m,n))
|
C#
using System;
public class GFG
{
static int LCSubStr( string s, string t,
int n, int m)
{
int [,] dp = new int [2, m + 1];
int res = 0;
for ( int i = 1; i <= n; i++)
{
for ( int j = 1; j <= m; j++)
{
if (s[i - 1] == t[j - 1])
{
dp[i % 2, j] = dp[(i - 1) % 2, j - 1] + 1;
if (dp[i % 2, j] > res)
res = dp[i % 2, j];
}
else dp[i % 2, j] = 0;
}
}
return res;
}
static public void Main (){
string X = "OldSite:GeeksforGeeks.org" ;
string Y = "NewSite:GeeksQuiz.com" ;
int m = X.Length;
int n = Y.Length;
Console.WriteLine(LCSubStr(X,Y,m,n));
}
}
|
Javascript
<script>
function LCSubStr(s, t, n, m)
{
var dp = Array(2).fill().map(()=>Array(m+ 1).fill(0));
var res = 0;
for ( var i = 1; i <= n; i++)
{
for ( var j = 1; j <= m; j++)
{
if (s.charAt(i - 1) == t.charAt(j - 1))
{
dp[i % 2][j] = dp[(i - 1) % 2][j - 1] + 1;
if (dp[i % 2][j] > res)
res = dp[i % 2][j];
}
else dp[i % 2][j] = 0;
}
}
return res;
}
var X = "OldSite:GeeksforGeeks.org" ;
var Y = "NewSite:GeeksQuiz.com" ;
var m = X.length;
var n = Y.length;
document.write(LCSubStr(X, Y, m, n));
</script>
|
Time Complexity: O(n*m)
Auxiliary Space: O(min(m,n))
Another Approach: (Using recursion)Â
Here is the recursive solution of the above approach.Â
C++
#include <iostream>
using namespace std;
string X, Y;
int lcs( int i, int j, int count)
{
if (i == 0 || j == 0)
return count;
if (X[i - 1] == Y[j - 1]) {
count = lcs(i - 1, j - 1, count + 1);
}
count = max(count,
max(lcs(i, j - 1, 0),
lcs(i - 1, j, 0)));
return count;
}
int main()
{
int n, m;
X = "abcdxyz" ;
Y = "xyzabcd" ;
n = X.size();
m = Y.size();
cout << lcs(n, m, 0);
return 0;
}
|
Java
import java.io.*;
class GFG {
static String X, Y;
static int lcs( int i, int j, int count)
{
if (i == 0 || j == 0 )
{
return count;
}
if (X.charAt(i - 1 )
== Y.charAt(j - 1 ))
{
count = lcs(i - 1 , j - 1 , count + 1 );
}
count = Math.max(count,
Math.max(lcs(i, j - 1 , 0 ),
lcs(i - 1 , j, 0 )));
return count;
}
public static void main(String[] args)
{
int n, m;
X = "abcdxyz" ;
Y = "xyzabcd" ;
n = X.length();
m = Y.length();
System.out.println(lcs(n, m, 0 ));
}
}
|
Python3
def lcs(i, j, count):
if (i = = 0 or j = = 0 ):
return count
if (X[i - 1 ] = = Y[j - 1 ]):
count = lcs(i - 1 , j - 1 , count + 1 )
count = max (count, max (lcs(i, j - 1 , 0 ),
lcs(i - 1 , j, 0 )))
return count
if __name__ = = "__main__" :
X = "abcdxyz"
Y = "xyzabcd"
n = len (X)
m = len (Y)
print (lcs(n, m, 0 ))
|
C#
using System;
class GFG {
static String X, Y;
static int lcs( int i, int j, int count)
{
if (i == 0 || j == 0) {
return count;
}
if (X[i - 1] == Y[j - 1]) {
count = lcs(i - 1, j - 1, count + 1);
}
count = Math.Max(count, Math.Max(lcs(i, j - 1, 0),
lcs(i - 1, j, 0)));
return count;
}
public static void Main()
{
int n, m;
X = "abcdxyz" ;
Y = "xyzabcd" ;
n = X.Length;
m = Y.Length;
Console.Write(lcs(n, m, 0));
}
}
|
Javascript
<script>
let X, Y;
function lcs(i, j, count)
{
if (i == 0 || j == 0)
return count;
if (X[i - 1] == Y[j - 1]) {
count = lcs(i - 1, j - 1, count + 1);
}
count = Math.max(count,
Math.max(lcs(i, j - 1, 0),
lcs(i - 1, j, 0)));
return count;
}
let n, m;
X = "abcdxyz" ;
Y = "xyzabcd" ;
n = X.length;
m = Y.length;
document.write(lcs(n, m, 0));
</script>
|
PHP
<?php
function lcs( $i , $j , $count , & $X , & $Y )
{
if ( $i == 0 || $j == 0)
return $count ;
if ( $X [ $i - 1] == $Y [ $j - 1])
{
$count = lcs( $i - 1, $j - 1,
$count + 1, $X , $Y );
}
$count = max( $count , lcs( $i , $j - 1, 0, $X , $Y ),
lcs( $i - 1, $j , 0, $X , $Y ));
return $count ;
}
$X = "abcdxyz" ;
$Y = "xyzabcd" ;
$n = strlen ( $X );
$m = strlen ( $Y );
echo lcs( $n , $m , 0, $X , $Y );
?>
|
Time complexity: O(2^max(m,n)) as the function is doing two recursive calls – lcs(i, j-1, 0) and lcs(i-1, j, 0) when characters at X[i-1] != Y[j-1]. So it will give a worst case time complexity as 2^N, where N = max(m, n), m and n is the length of X and Y string.
Auxiliary Space: O(1): as the function call is not using any extra space (function is just using a recursive call stack which we generally doesn’t consider in auxiliary space).
Maximum Space Optimization:Ad
Share your thoughts in the comments
Please Login to comment...