Print the longest common substring
Given two strings ‘X’ and ‘Y’, print the length of the longest common substring. If two or more substrings have the same value for the longest common substring, then print any one of them.
Examples:
Input : X = "GeeksforGeeks",
Y = "GeeksQuiz"
Output : Geeks
Input : X = "zxabcdezy",
Y = "yzabcdezx"
Output : abcdez
We have discussed a solution to find the length of the longest common string. In this post, we have discussed printing common string is discussed.
Naive Approach: Let strings X and Y be the lengths m and n respectively. Generate all possible substrings of X which requires a time complexity of O(m2) and search each substring in the string Y which can be achieved in O(n) time complexity using the KMP algorithm. Overall time complexity will be O(n * m2).
Efficient Approach: It is based on the dynamic programming implementation explained in this post. The longest suffix matrix LCSuff[][] is build up and the index of the cell having the maximum value is tracked. Let that index be represented by (row, col) pair. Now the final longest common substring is built with the help of that index by diagonally traversing up the LCSuff[][] matrix until LCSuff[row][col] != 0 and during the iteration obtaining the characters either from X[row-1] or Y[col-1] and adding them from right to left in the resultant common string.
Implementation:
C++
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
void printLCSubStr( char * X, char * Y, int m, int n)
{
int LCSuff[m + 1][n + 1];
int len = 0;
int row, col;
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;
if (len < LCSuff[i][j]) {
len = LCSuff[i][j];
row = i;
col = j;
}
}
else
LCSuff[i][j] = 0;
}
}
if (len == 0) {
cout << "No Common Substring" ;
return ;
}
char * resultStr = ( char *) malloc ((len + 1) * sizeof ( char ));
while (LCSuff[row][col] != 0) {
resultStr[--len] = X[row - 1];
row--;
col--;
}
cout << resultStr;
}
int main()
{
char X[] = "OldSite:GeeksforGeeks.org" ;
char Y[] = "NewSite:GeeksQuiz.com" ;
int m = strlen (X);
int n = strlen (Y);
printLCSubStr(X, Y, m, n);
return 0;
}
|
Java
public class Longest_common_substr {
static void printLCSubStr(String X, String Y, int m, int n)
{
int [][] LCSuff = new int [m + 1 ][n + 1 ];
int len = 0 ;
int row = 0 , col = 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.charAt(i - 1 ) == Y.charAt(j - 1 )) {
LCSuff[i][j] = LCSuff[i - 1 ][j - 1 ] + 1 ;
if (len < LCSuff[i][j]) {
len = LCSuff[i][j];
row = i;
col = j;
}
}
else
LCSuff[i][j] = 0 ;
}
}
if (len == 0 ) {
System.out.println( "No Common Substring" );
return ;
}
String resultStr = "" ;
while (LCSuff[row][col] != 0 ) {
resultStr = X.charAt(row - 1 ) + resultStr;
--len;
row--;
col--;
}
System.out.println(resultStr);
}
public static void main(String args[])
{
String X = "OldSite:GeeksforGeeks.org" ;
String Y = "NewSite:GeeksQuiz.com" ;
int m = X.length();
int n = Y.length();
printLCSubStr(X, Y, m, n);
}
}
|
Python3
C#
Javascript
Time Complexity: O(m*n).
Auxiliary Space: O(m*n).
Space Optimized Approach: The auxiliary space used by the solution above is O(m*n), where m and n are lengths of string X and Y. The space used by the above solution can be reduced to O(2*n). A variable end is used to store the ending point of the longest common substring in string X and variable maxlen is used to store the length of the longest common substring.
Suppose we are at DP state when the length of X is i and length of Y is j, the result of which is stored in len[i][j].
Now if X[i-1] == Y[j-1], then len[i][j] = 1 + len[i-1][j-1], that is result of current row in matrix len[][] depends on values from previous row. Hence, the required length of the longest common substring can be obtained by maintaining values of two consecutive rows only, thereby reducing space requirements to O(2*n).
To print the longest common substring, we use a variable end. When len[i][j] is calculated, it is compared with maxlen. If maxlen is less than len[i][j], then end is updated to i-1 to show that longest common substring ends at index i-1 in X and maxlen is updated to len[i][j]. The longest common substring then is from index end – maxlen + 1 to index end in X.
A variable currRow is used to represent that either row 0 or row 1 of len[2][n] matrix is currently used to find the length. Initially, row 0 is used as the current row for the case when the length of string X is zero. At the end of each iteration, the current row is made the previous row and the previous row is made the new current row.
Given below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
string LCSubStr(string X, string Y)
{
int m = X.length();
int n = Y.length();
int result = 0;
int end;
int len[2][n + 1];
int currRow = 0;
for ( int i = 0; i <= m; i++) {
for ( int j = 0; j <= n; j++) {
if (i == 0 || j == 0) {
len[currRow][j] = 0;
}
else if (X[i - 1] == Y[j - 1]) {
len[currRow][j] = len[1 - currRow][j - 1] + 1;
if (len[currRow][j] > result) {
result = len[currRow][j];
end = i - 1;
}
}
else {
len[currRow][j] = 0;
}
}
currRow = 1 - currRow;
}
if (result == 0) {
return "-1" ;
}
return X.substr(end - result + 1, result);
}
int main()
{
string X = "GeeksforGeeks" ;
string Y = "GeeksQuiz" ;
cout << LCSubStr(X, Y);
return 0;
}
|
Java
public class GFG {
static String LCSubStr(String X, String Y) {
int m = X.length();
int n = Y.length();
int result = 0 ;
int end = 0 ;
int len[][] = new int [ 2 ][m];
int currRow = 0 ;
for ( int i = 0 ; i <= m; i++) {
for ( int j = 0 ; j <= n; j++) {
if (i == 0 || j == 0 ) {
len[currRow][j] = 0 ;
} else if (X.charAt(i - 1 ) == Y.charAt(j - 1 )) {
len[currRow][j] = len[ 1 - currRow][j - 1 ] + 1 ;
if (len[currRow][j] > result) {
result = len[currRow][j];
end = i - 1 ;
}
} else {
len[currRow][j] = 0 ;
}
}
currRow = 1 - currRow;
}
if (result == 0 ) {
return "-1" ;
}
return X.substring(end - result + 1 , result);
}
public static void main(String[] args) {
String X = "GeeksforGeeks" ;
String Y = "GeeksQuiz" ;
System.out.println(LCSubStr(X, Y));
}
}
|
Python3
def LCSubStr(X, Y):
m = len (X)
n = len (Y)
result = 0
end = 0
length = [[ 0 for j in range (m)]
for i in range ( 2 )]
currRow = 0
for i in range ( 0 , m + 1 ):
for j in range ( 0 , n + 1 ):
if (i = = 0 or j = = 0 ):
length[currRow][j] = 0
elif (X[i - 1 ] = = Y[j - 1 ]):
length[currRow][j] = length[ 1 - currRow][j - 1 ] + 1
if (length[currRow][j] > result):
result = length[currRow][j]
end = i - 1
else :
length[currRow][j] = 0
currRow = 1 - currRow
if (result = = 0 ):
return "-1"
return X[end - result + 1 : end + 1 ]
if __name__ = = "__main__" :
X = "GeeksforGeeks"
Y = "GeeksQuiz"
print (LCSubStr(X, Y))
|
C#
Javascript
<script>
function LCSubStr(X,Y)
{
let m = X.length;
let n = Y.length;
let result = 0;
let end;
let len= new Array(2);
for (let i=0;i<len.length;i++)
{
len[i]= new Array(n);
for (let j=0;j<n;j++)
{
len[i][j]=0;
}
}
let currRow = 0;
for (let i = 0; i <= m; i++) {
for (let j = 0; j <= n; j++) {
if (i == 0 || j == 0) {
len[currRow][j] = 0;
}
else if (X[i - 1] == Y[j - 1]) {
len[currRow][j] = len[1 - currRow][j - 1] + 1;
if (len[currRow][j] > result) {
result = len[currRow][j];
end = i - 1;
}
}
else {
len[currRow][j] = 0;
}
}
currRow = 1 - currRow;
}
if (result == 0) {
return "-1" ;
}
return X.substr(end - result + 1, result);
}
let X = "GeeksforGeeks" ;
let Y = "GeeksQuiz" ;
document.write(LCSubStr(X, Y));
</script>
|
Time Complexity: O(m*n)
Auxiliary Space: O(n)
This approach has been suggested by nik1996.
Last Updated :
15 Jul, 2022
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...