Given a string str, find the longest repeating non-overlapping substring in it. In other words find 2 identical substrings of maximum length which do not overlap. If there exists more than one such substring return any of them.
Examples:
Input : str = "geeksforgeeks"
Output : geeks
Input : str = "aab"
Output : a
Input : str = "aabaabaaba"
Output : aaba
Input : str = "aaaaaaaaaaa"
Output : aaaaa
Input : str = "banana"
Output : an
or na
Naive Solution : The problem can be solved easily by taking all the possible substrings and for all the substrings check it for the remaining(non-overlapping) string if there exists an identical substring. There are O(n2) total substrings and checking them against the remaining string will take O(n) time. So overall time complexity of above solution is O(n3).
Dynamic Programming : This problem can be solved in O(n2) time using Dynamic Programming. The basic idea is to find the longest repeating suffix for all prefixes in the string str.
Length of longest non-repeating substring can be recursively
defined as below.
LCSRe(i, j) stores length of the matching and
non-overlapping substrings ending
with i'th and j'th characters.
If str[i-1] == str[j-1] && (j-i) > LCSRe(i-1, j-1)
LCSRe(i, j) = LCSRe(i-1, j-1) + 1,
Else
LCSRe(i, j) = 0
Where i varies from 1 to n and
j varies from i+1 to n
To avoid overlapping we have to ensure that the length of suffix is less than (j-i) at any instant.
The maximum value of LCSRe(i, j) provides the length of the longest repeating substring and the substring itself can be found using the length and the ending index of the common suffix.
Below is the implementation of the recurrence.
C++
#include<bits/stdc++.h>
using namespace std;
string longestRepeatedSubstring(string str)
{
int n = str.length();
int LCSRe[n+1][n+1];
memset (LCSRe, 0, sizeof (LCSRe));
string res;
int res_length = 0;
int i, index = 0;
for (i=1; i<=n; i++)
{
for ( int j=i+1; j<=n; j++)
{
if (str[i-1] == str[j-1] &&
LCSRe[i-1][j-1] < (j - i))
{
LCSRe[i][j] = LCSRe[i-1][j-1] + 1;
if (LCSRe[i][j] > res_length)
{
res_length = LCSRe[i][j];
index = max(i, index);
}
}
else
LCSRe[i][j] = 0;
}
}
if (res_length > 0)
for (i = index - res_length + 1; i <= index; i++)
res.push_back(str[i-1]);
return res;
}
int main()
{
string str = "geeksforgeeks" ;
cout << longestRepeatedSubstring(str);
return 0;
}
|
Java
class GFG {
static String longestRepeatedSubstring(String str) {
int n = str.length();
int LCSRe[][] = new int [n + 1 ][n + 1 ];
String res = "" ;
int res_length = 0 ;
int i, index = 0 ;
for (i = 1 ; i <= n; i++) {
for ( int j = i + 1 ; j <= n; j++) {
if (str.charAt(i - 1 ) == str.charAt(j - 1 )
&& LCSRe[i - 1 ][j - 1 ] < (j - i)) {
LCSRe[i][j] = LCSRe[i - 1 ][j - 1 ] + 1 ;
if (LCSRe[i][j] > res_length) {
res_length = LCSRe[i][j];
index = Math.max(i, index);
}
} else {
LCSRe[i][j] = 0 ;
}
}
}
if (res_length > 0 ) {
for (i = index - res_length + 1 ; i <= index; i++) {
res += str.charAt(i - 1 );
}
}
return res;
}
public static void main(String[] args) {
String str = "geeksforgeeks" ;
System.out.println(longestRepeatedSubstring(str));
}
}
|
Python 3
def longestRepeatedSubstring( str ):
n = len ( str )
LCSRe = [[ 0 for x in range (n + 1 )]
for y in range (n + 1 )]
res = ""
res_length = 0
index = 0
for i in range ( 1 , n + 1 ):
for j in range (i + 1 , n + 1 ):
if ( str [i - 1 ] = = str [j - 1 ] and
LCSRe[i - 1 ][j - 1 ] < (j - i)):
LCSRe[i][j] = LCSRe[i - 1 ][j - 1 ] + 1
if (LCSRe[i][j] > res_length):
res_length = LCSRe[i][j]
index = max (i, index)
else :
LCSRe[i][j] = 0
if (res_length > 0 ):
for i in range (index - res_length + 1 ,
index + 1 ):
res = res + str [i - 1 ]
return res
if __name__ = = "__main__" :
str = "geeksforgeeks"
print (longestRepeatedSubstring( str ))
|
C#
using System;
public class GFG {
static String longestRepeatedSubstring(String str) {
int n = str.Length;
int [,]LCSRe = new int [n + 1,n + 1];
String res = "" ;
int res_length = 0;
int i, index = 0;
for (i = 1; i <= n; i++) {
for ( int j = i + 1; j <= n; j++) {
if (str[i - 1] == str[j - 1]
&& LCSRe[i - 1,j - 1] < (j - i)) {
LCSRe[i,j] = LCSRe[i - 1,j - 1] + 1;
if (LCSRe[i,j] > res_length) {
res_length = LCSRe[i,j];
index = Math.Max(i, index);
}
} else {
LCSRe[i,j] = 0;
}
}
}
if (res_length > 0) {
for (i = index - res_length + 1; i <= index; i++) {
res += str[i - 1];
}
}
return res;
}
public static void Main() {
String str = "geeksforgeeks" ;
Console.WriteLine(longestRepeatedSubstring(str));
}
}
|
Javascript
<script>
function longestRepeatedSubstring(str)
{
let n = str.length;
let LCSRe = new Array(n+1);
for (let i = 0; i < n + 1; i++)
{
LCSRe[i] = new Array(n+1);
}
for (let i = 0; i < n + 1; i++)
{
for (let j = 0; j < n + 1; j++)
{
LCSRe[i][j] = 0;
}
}
let res = "" ;
let res_length = 0;
let i, index = 0;
for (i = 1; i <= n; i++)
{
for (let j = i + 1; j <= n; j++)
{
if (str[i-1] == str[j-1]
&& LCSRe[i - 1][j - 1] < (j - i))
{
LCSRe[i][j] = LCSRe[i - 1][j - 1] + 1;
if (LCSRe[i][j] > res_length)
{
res_length = LCSRe[i][j];
index = Math.max(i, index);
}
}
else
{
LCSRe[i][j] = 0;
}
}
}
if (res_length > 0) {
for (i = index - res_length + 1; i <= index; i++) {
res += str.charAt(i - 1);
}
}
return res;
}
let str= "geeksforgeeks" ;
document.write(longestRepeatedSubstring(str));
</script>
|
Time Complexity: O(n2)
Auxiliary Space: O(n2)
References:
https://www.geeksforgeeks.org/longest-common-substring/
This article is contributed by Ayush Khanduri. If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.