Longest repeating and nonoverlapping substring (original) (raw)

Given a **string s, the task is to find the longest repeating non-overlapping substring in it. In other words, find 2 identical substrings of **maximum length which do not overlap. Return -1 if no such string exists.

**Note: Multiple Answers are possible but we have to return the **substring whose first occurrence is earlier.

**Examples:

**Input: s ="acdcdacdc"
**Output: "acdc"
**Explanation: The string "acdc" is the longest Substring of s which is repeating but not overlapping.

**Input: s = "geeksforgeeks"
**Output: "geeks"
**Explanation: The string "geeks" is the longest subString of s which is repeating but not overlapping.

Table of Content

Using Brute Force Method - O(n^3) Time and O(n) Space

The idea is to **generate all the possible substrings and check if the substring exists in the **remaining string. If substring exists and its **length is **greater than answer substring, then set **answer to current substring.

C++ `

// C++ program to find longest repeating // and non-overlapping substring // using recursion #include <bits/stdc++.h> using namespace std;

string longestSubstring(string& s) { int n = s.length();

string ans = "";
int len = 0;

int i = 0, j = 0;

while (i < n && j < n) {

    string curr = s.substr(i, j - i + 1);

    // If substring exists, compare its length
    // with ans
    if (s.find(curr, j + 1) != string::npos 
        && j - i + 1 > len) {
        len = j - i + 1;
        ans = curr;
    }

    // Otherwise increment i
    else
        i++;

    j++;
}

return len > 0 ? ans : "-1";

}

int main() { string s = "geeksforgeeks"; cout << longestSubstring(s) << endl; return 0; }

Java

// Java program to find longest repeating // and non-overlapping substring // using recursion class GfG {

static String longestSubstring(String s) {
    int n = s.length();

    String ans = "";
    int len = 0;

    int i = 0, j = 0;

    while (i < n && j < n) {

        String curr = s.substring(i, j + 1);

        // If substring exists, compare its length
        // with ans
        if (s.indexOf(curr, j + 1) != -1
            && j - i + 1 > len) {
            len = j - i + 1;
            ans = curr;
        }

        // Otherwise increment i
        else
            i++;

        j++;
    }

    return len > 0 ? ans : "-1";
}

public static void main(String[] args) {
    String s = "geeksforgeeks";
    System.out.println(longestSubstring(s));
}

}

Python

Python program to find longest repeating

and non-overlapping substring

using recursion

def longestSubstring(s): n = len(s)

ans = ""
lenAns = 0

i, j = 0, 0

while i < n and j < n:

    curr = s[i:j + 1]

    # If substring exists, compare its length
    # with ans
    if s.find(curr, j + 1) != -1 and j - i + 1 > lenAns:
        lenAns = j - i + 1
        ans = curr

    # Otherwise increment i
    else:
        i += 1

    j += 1

if lenAns > 0:
    return ans
return "-1"

if name == "main": s = "geeksforgeeks" print(longestSubstring(s))

C#

// C# program to find longest repeating // and non-overlapping substring // using recursion

using System;

class GfG {

static string longestSubstring(string s) {
    int n = s.Length;

    string ans = "";
    int len = 0;

    int i = 0, j = 0;

    while (i < n && j < n) {

        string curr = s.Substring(i, j - i + 1);

        // If substring exists, compare its length
        // with ans
        if (s.IndexOf(curr, j + 1) != -1
            && j - i + 1 > len) {
            len = j - i + 1;
            ans = curr;
        }

        // Otherwise increment i
        else
            i++;

        j++;
    }

    return len > 0 ? ans : "-1";
}

static void Main(string[] args) {
    string s = "geeksforgeeks";
    Console.WriteLine(longestSubstring(s));
}

}

JavaScript

// JavaScript program to find longest repeating // and non-overlapping substring // using recursion

function longestSubstring(s) { const n = s.length;

let ans = "";
let len = 0;

let i = 0, j = 0;

while (i < n && j < n) {

    const curr = s.substring(i, j + 1);

    // If substring exists, compare its length
    // with ans
    if (s.indexOf(curr, j + 1) !== -1
        && j - i + 1 > len) {
        len = j - i + 1;
        ans = curr;
    }

    // Otherwise increment i
    else
        i++;

    j++;
}

return len > 0 ? ans : "-1";

}

const s = "geeksforgeeks"; console.log(longestSubstring(s));

`

Using Top-Down DP (Memoization) - O(n^2) Time and O(n^2) Space

The approach is to compute the longest repeating suffix for all prefix pairs in the string s. For indices i and **j, if **s[i] == s[j], then recursively compute **suffix(i+1, j+1) and set suffix(i, j) as **min(suffix(i+1, j+1) + 1, j - i - 1) to **prevent overlap. If the characters do not match, **set suffix(i, j) = 0.

**Note:

// C++ program to find longest repeating // and non-overlapping substring // using memoization #include <bits/stdc++.h> using namespace std;

int findSuffix(int i, int j, string &s, vector<vector> &memo) {

// base case
if (j == s.length())
    return 0;

// return memoized value
if (memo[i][j] != -1)
    return memo[i][j];

// if characters match
if (s[i] == s[j]) {
    memo[i][j] = 1 + min(findSuffix(i + 1, j + 1, s, memo),
                         j - i - 1);
}
else {
    memo[i][j] = 0;
}

return memo[i][j];

}

string longestSubstring(string s) {

int n = s.length();

vector<vector<int>> memo(n, vector<int>(n, -1));

// find length of non-overlapping
// substrings for all pairs (i,j)
for (int i = 0; i < n; i++) {
    for (int j = i + 1; j < n; j++) {
        findSuffix(i, j, s, memo);
    }
}

string ans = "";
int ansLen = 0;

// If length of suffix is greater
// than ansLen, update ans and ansLen
for (int i = 0; i < n; i++) {
    for (int j = i + 1; j < n; j++) {
        if (memo[i][j] > ansLen) {
            ansLen = memo[i][j];
            ans = s.substr(i, ansLen);
        }
    }
}

return ansLen > 0 ? ans : "-1";

}

int main() { string s = "geeksforgeeks"; cout << longestSubstring(s) << endl; return 0; }

Java

// Java program to find longest repeating // and non-overlapping substring // using memoization import java.util.Arrays;

class GfG {

static int findSuffix(int i, int j, String s,
                      int[][] memo) {

    // base case
    if (j == s.length())
        return 0;

    // return memoized value
    if (memo[i][j] != -1)
        return memo[i][j];

    // if characters match
    if (s.charAt(i) == s.charAt(j)) {
        memo[i][j] = 1
                     + Math.min(findSuffix(i + 1, j + 1,
                                           s, memo),
                                j - i - 1);
    }
    else {
        memo[i][j] = 0;
    }

    return memo[i][j];
}

static String longestSubstring(String s) {

    int n = s.length();

    int[][] memo = new int[n][n];
    for (int[] row : memo) {
        Arrays.fill(row, -1);
    }

    // find length of non-overlapping
    // substrings for all pairs (i, j)
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            findSuffix(i, j, s, memo);
        }
    }

    String ans = "";
    int ansLen = 0;

    // If length of suffix is greater
    // than ansLen, update ans and ansLen
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            if (memo[i][j] > ansLen) {
                ansLen = memo[i][j];
                ans = s.substring(i, i + ansLen);
            }
        }
    }

    return ansLen > 0 ? ans : "-1";
}

public static void main(String[] args) {
    String s = "geeksforgeeks";
    System.out.println(longestSubstring(s));
}

}

Python

Python program to find longest repeating

and non-overlapping substring

using memoization

def findSuffix(i, j, s, memo):

# base case
if j == len(s):
    return 0

# return memoized value
if memo[i][j] != -1:
    return memo[i][j]

# if characters match
if s[i] == s[j]:
    memo[i][j] = 1 + min(findSuffix(i + 1, j + 1, s, memo), \
                         j - i - 1)
else:
    memo[i][j] = 0

return memo[i][j]

def longestSubstring(s): n = len(s)

memo = [[-1] * n for _ in range(n)]

# find length of non-overlapping
# substrings for all pairs (i, j)
for i in range(n):
    for j in range(i + 1, n):
        findSuffix(i, j, s, memo)

ans = ""
ansLen = 0

# If length of suffix is greater
# than ansLen, update ans and ansLen
for i in range(n):
    for j in range(i + 1, n):
        if memo[i][j] > ansLen:
            ansLen = memo[i][j]
            ans = s[i:i + ansLen]

if ansLen > 0:
    return ans

return "-1"

if name == "main": s = "geeksforgeeks" print(longestSubstring(s))

C#

// C# program to find longest repeating // and non-overlapping substring // using memoization

using System;

class GfG {

static int findSuffix(int i, int j, string s,
                      int[, ] memo) {

    // base case
    if (j == s.Length)
        return 0;

    // return memoized value
    if (memo[i, j] != -1)
        return memo[i, j];

    // if characters match
    if (s[i] == s[j]) {
        memo[i, j] = 1
                     + Math.Min(findSuffix(i + 1, j + 1,
                                           s, memo),
                                j - i - 1);
    }
    else {
        memo[i, j] = 0;
    }

    return memo[i, j];
}

static string longestSubstring(string s) {
    int n = s.Length;

    int[, ] memo = new int[n, n];
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            memo[i, j] = -1;
        }
    }

    // find length of non-overlapping
    // substrings for all pairs (i, j)
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            findSuffix(i, j, s, memo);
        }
    }

    string ans = "";
    int ansLen = 0;

    // If length of suffix is greater
    // than ansLen, update ans and ansLen
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            if (memo[i, j] > ansLen) {
                ansLen = memo[i, j];
                ans = s.Substring(i, ansLen);
            }
        }
    }

    return ansLen > 0 ? ans : "-1";
}

static void Main(string[] args) {
    string s = "geeksforgeeks";
    Console.WriteLine(longestSubstring(s));
}

}

JavaScript

// JavaScript program to find longest repeating // and non-overlapping substring // using memoization

function findSuffix(i, j, s, memo) {

// base case
if (j === s.length)
    return 0;

// return memoized value
if (memo[i][j] !== -1)
    return memo[i][j];

// if characters match
if (s[i] === s[j]) {
    memo[i][j]
        = 1
          + Math.min(findSuffix(i + 1, j + 1, s, memo),
                     j - i - 1);
}
else {
    memo[i][j] = 0;
}

return memo[i][j];

}

function longestSubstring(s) { const n = s.length;

const memo
    = Array.from({length : n}, () => Array(n).fill(-1));

// find length of non-overlapping
// substrings for all pairs (i, j)
for (let i = 0; i < n; i++) {
    for (let j = i + 1; j < n; j++) {
        findSuffix(i, j, s, memo);
    }
}

let ans = "";
let ansLen = 0;

// If length of suffix is greater
// than ansLen, update ans and ansLen
for (let i = 0; i < n; i++) {
    for (let j = i + 1; j < n; j++) {
        if (memo[i][j] > ansLen) {
            ansLen = memo[i][j];
            ans = s.substring(i, i + ansLen);
        }
    }
}

return ansLen > 0 ? ans : "-1";

}

const s = "geeksforgeeks"; console.log(longestSubstring(s));

`

Using Bottom-Up DP (Tabulation) - O(n^2) Time and O(n^2) Space

The idea is to create a 2D matrix of **size (n+1)*(n+1) and calculate the longest repeating suffixes for all index **pairs (i, j) iteratively. We start from the **end of the string and work backwards to fill the table. For each (i, j), if **s[i] == s[j], we set **suffix[i][j] to min(suffix[i+1][j+1]+1, j-i-1) to avoid overlap; otherwise, **suffix[i][j] = 0.

C++ `

// C++ program to find longest repeating // and non-overlapping substring // using tabulation #include <bits/stdc++.h> using namespace std;

string longestSubstring(string s) {

int n = s.length();
vector<vector<int>> dp(n+1, vector<int>(n+1, 0));

string ans = "";
int ansLen = 0;

// find length of non-overlapping 
// substrings for all pairs (i,j)
for (int i=n-1; i>=0; i--) {
    for (int j=n-1; j>i; j--) {
        
        // if characters match, set value 
        // and compare with ansLen.
        if (s[i]==s[j]) {
            dp[i][j] = 1 + min(dp[i+1][j+1], j-i-1);
            
            if (dp[i][j]>=ansLen) {
                ansLen = dp[i][j];
                ans = s.substr(i, ansLen);
            }
        }
    }
}

return ansLen>0?ans:"-1";

}

int main() { string s = "geeksforgeeks"; cout << longestSubstring(s) << endl; return 0; }

Java

// Java program to find longest repeating // and non-overlapping substring // using tabulation

class GfG {

static String longestSubstring(String s) {

    int n = s.length();
    int[][] dp = new int[n + 1][n + 1];
    
    String ans = "";
    int ansLen = 0;
    
    // find length of non-overlapping 
    // substrings for all pairs (i, j)
    for (int i = n - 1; i >= 0; i--) {
        for (int j = n - 1; j > i; j--) {
            
            // if characters match, set value 
            // and compare with ansLen.
            if (s.charAt(i) == s.charAt(j)) {
                dp[i][j] = 1 + Math.min(dp[i + 1][j + 1], j - i - 1);
                
                if (dp[i][j] >= ansLen) {
                    ansLen = dp[i][j];
                    ans = s.substring(i, i + ansLen);
                }
            }
        }
    }
    
    return ansLen > 0 ? ans : "-1";
}

public static void main(String[] args) {
    String s = "geeksforgeeks";
    System.out.println(longestSubstring(s));
}

}

Python

Python program to find longest repeating

and non-overlapping substring

using tabulation

def longestSubstring(s): n = len(s) dp = [[0] * (n + 1) for _ in range(n + 1)]

ans = ""
ansLen = 0

# find length of non-overlapping 
# substrings for all pairs (i, j)
for i in range(n - 1, -1, -1):
    for j in range(n - 1, i, -1):
        
        # if characters match, set value 
        # and compare with ansLen.
        if s[i] == s[j]:
            dp[i][j] = 1 + min(dp[i + 1][j + 1], j - i - 1)
            
            if dp[i][j] >= ansLen:
                ansLen = dp[i][j]
                ans = s[i:i + ansLen]

return ans if ansLen > 0 else "-1"

if name == "main": s = "geeksforgeeks" print(longestSubstring(s))

C#

// C# program to find longest repeating // and non-overlapping substring // using tabulation

using System;

class GfG {

static string longestSubstring(string s) {
    int n = s.Length;
    int[,] dp = new int[n + 1, n + 1];
    
    string ans = "";
    int ansLen = 0;
    
    // find length of non-overlapping 
    // substrings for all pairs (i, j)
    for (int i = n - 1; i >= 0; i--) {
        for (int j = n - 1; j > i; j--) {
            
            // if characters match, set value 
            // and compare with ansLen.
            if (s[i] == s[j]) {
                dp[i, j] = 1 + Math.Min(dp[i + 1, j + 1], j - i - 1);
                
                if (dp[i, j] >= ansLen) {
                    ansLen = dp[i, j];
                    ans = s.Substring(i, ansLen);
                }
            }
        }
    }
    
    return ansLen > 0 ? ans : "-1";
}

static void Main(string[] args) {
    string s = "geeksforgeeks";
    Console.WriteLine(longestSubstring(s));
}

}

JavaScript

// JavaScript program to find longest repeating // and non-overlapping substring // using tabulation

function longestSubstring(s) { const n = s.length; const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(0));

let ans = "";
let ansLen = 0;

// find length of non-overlapping 
// substrings for all pairs (i, j)
for (let i = n - 1; i >= 0; i--) {
    for (let j = n - 1; j > i; j--) {
        
        // if characters match, set value 
        // and compare with ansLen.
        if (s[i] === s[j]) {
            dp[i][j] = 1 + Math.min(dp[i + 1][j + 1], j - i - 1);
            
            if (dp[i][j] >= ansLen) {
                ansLen = dp[i][j];
                ans = s.substring(i, i + ansLen);
            }
        }
    }
}

return ansLen > 0 ? ans : "-1";

}

const s = "geeksforgeeks"; console.log(longestSubstring(s));

`

Using Space Optimized DP – O(n^2) Time and O(n) Space

The idea is to use a single 1D array instead of a 2D matrix by keeping track of only the "next row" values required to compute suffix[i][j]. Since each value suffix[i][j]** depends only on **suffix[i+1][j+1] in the row below, we can maintain the previous row's values in a 1D array and update them iteratively for each row.

C++ `

// C++ program to find longest repeating // and non-overlapping substring // using space optimised #include <bits/stdc++.h> using namespace std;

string longestSubstring(string s) {

int n = s.length();
vector<int> dp(n+1,0);

string ans = "";
int ansLen = 0;

// find length of non-overlapping 
// substrings for all pairs (i,j)
for (int i=n-1; i>=0; i--) {

    for (int j=i; j<n; j++) {
        
        // if characters match, set value 
        // and compare with ansLen.
        if (s[i]==s[j]) {
            dp[j] = 1 + min(dp[j+1], j-i-1);
            
            if (dp[j]>=ansLen) {
                ansLen = dp[j];
                ans = s.substr(i, ansLen);
            }
        }
        else dp[j] = 0;
    }
}

return ansLen>0?ans:"-1";

}

int main() { string s = "geeksforgeeks"; cout << longestSubstring(s) << endl; return 0; }

Java

// Java program to find longest repeating // and non-overlapping substring // using space optimised

class GfG {

static String longestSubstring(String s) {

    int n = s.length();
    int[] dp = new int[n + 1];
    
    String ans = "";
    int ansLen = 0;
    
    // find length of non-overlapping 
    // substrings for all pairs (i, j)
    for (int i = n - 1; i >= 0; i--) {
        for (int j = i; j < n; j++) {
            
            // if characters match, set value 
            // and compare with ansLen.
            if (s.charAt(i) == s.charAt(j)) {
                dp[j] = 1 + Math.min(dp[j + 1], j - i - 1);
                
                if (dp[j] >= ansLen) {
                    ansLen = dp[j];
                    ans = s.substring(i, i + ansLen);
                }
            } else {
                dp[j] = 0;
            }
        }
    }
    
    return ansLen > 0 ? ans : "-1";
}

public static void main(String[] args) {
    String s = "geeksforgeeks";
    System.out.println(longestSubstring(s));
}

}

Python

Python program to find longest repeating

and non-overlapping substring

using space optimised

def longestSubstring(s): n = len(s) dp = [0] * (n + 1)

ans = ""
ansLen = 0

# find length of non-overlapping 
# substrings for all pairs (i, j)
for i in range(n - 1, -1, -1):
    for j in range(i, n):
        
        # if characters match, set value 
        # and compare with ansLen.
        if s[i] == s[j]:
            dp[j] = 1 + min(dp[j + 1], j - i - 1)
            
            if dp[j] >= ansLen:
                ansLen = dp[j]
                ans = s[i:i + ansLen]
        else:
            dp[j] = 0

return ans if ansLen > 0 else "-1"

if name == "main": s = "geeksforgeeks" print(longestSubstring(s))

C#

// C# program to find longest repeating // and non-overlapping substring // using space optimised

using System;

class GfG {

static string longestSubstring(string s) {
    int n = s.Length;
    int[] dp = new int[n + 1];
    
    string ans = "";
    int ansLen = 0;
    
    // find length of non-overlapping 
    // substrings for all pairs (i, j)
    for (int i = n - 1; i >= 0; i--) {
        for (int j = i; j < n; j++) {
            
            // if characters match, set value 
            // and compare with ansLen.
            if (s[i] == s[j]) {
                dp[j] = 1 + Math.Min(dp[j + 1], j - i - 1);
                
                if (dp[j] >= ansLen) {
                    ansLen = dp[j];
                    ans = s.Substring(i, ansLen);
                }
            } else {
                dp[j] = 0;
            }
        }
    }
    
    return ansLen > 0 ? ans : "-1";
}

static void Main(string[] args) {
    string s = "geeksforgeeks";
    Console.WriteLine(longestSubstring(s));
}

}

JavaScript

// JavaScript program to find longest repeating // and non-overlapping substring // using space optimised

function longestSubstring(s) { const n = s.length; const dp = new Array(n + 1).fill(0);

let ans = "";
let ansLen = 0;

// find length of non-overlapping 
// substrings for all pairs (i, j)
for (let i = n - 1; i >= 0; i--) {
    for (let j = i; j < n; j++) {
        
        // if characters match, set value 
        // and compare with ansLen.
        if (s[i] === s[j]) {
            dp[j] = 1 + Math.min(dp[j + 1], j - i - 1);
            
            if (dp[j] >= ansLen) {
                ansLen = dp[j];
                ans = s.substring(i, i + ansLen);
            }
        } else {
            dp[j] = 0;
        }
    }
}

return ansLen > 0 ? ans : "-1";

}

const s = "geeksforgeeks"; console.log(longestSubstring(s));

`

**Related articles: