Longest Repeating Subsequence

Last Updated : 20 Jul, 2026

Given string str, find the length of the longest repeating subsequence such that it can be found twice in the given string.

The two identified subsequences A and B can use the same ith character from string s if and only if that ith character has different indices in A and B. For example, A = "xax" and B = "xax" then the index of the first "x" must be different in the original string for A and B.

Examples:

Input: s = "axxzxy"
Output: 2
Explanation: The given array with indexes looks like
a x x z x y
0 1 2 3 4 5
The longest subsequence is "xx". It appears twice as explained below.
subsequence A
x x
0 1 <-- index of subsequence A
------
1 2 <-- index of s
subsequence B
x x
0 1 <-- index of subsequence B
------
2 4 <-- index of s
We are able to use character 'x' (at index 2 in s) in both subsequences as it appears on index 1 in subsequence A and index 0 in subsequence B.

Input: s = "axxxy"
Output: 2
Explanation: The given array with indexes looks like
a x x x y
0 1 2 3 4
The longest subsequence is "xx". It appears twice as explained below.
subsequence A
x x
0 1 <-- index of subsequence A
------
1 2 <-- index of s
subsequence B
x x
0 1 <-- index of subsequence B
------
2 3 <-- index of s
We are able to use character 'x' (at index 2 in s) in both subsequencesas it appears on index 1 in subsequence A and index 0 in subsequence B.

Try It Yourself
redirect icon

[Naive Approach] Using Recursion - O(2 ^ n) time and O(n) space

This problem is a variation of the Longest Common Subsequence (LCS) problem. We compare the string with itself and find the LCS, with an additional condition that matching characters must come from different indices. This ensures that the same character position is not used in both subsequences.

The idea is to compare the characters at index i and j of s and the indices i and j. Two cases arise:

1. If the characters of the string match (s[i-1] == s[j-1]) and their indices are different (i != j), then make a recursive call for the remaining string (i-1 and j-1) and add 1 to the result.

longestRepeatingSubsequence(i, j, s) = 1 + longestRepeatingSubsequence(i-1, j-1, s)

2. If the characters do not match or the indices are the same, make two recursive calls:

longestRepeatingSubsequence(i, j, str) = max(longestRepeatingSubsequence(i-1, j, str), longestRepeatingSubsequence(i, j-1, str))

Base Case:

If either of the strings becomes empty (i == 0 or j == 0), return 0.

C++
#include <bits/stdc++.h>
using namespace std;

int findLongestRepeatingSubsequence(int i, int j, string &s)
{

    // base case
    if (i == 0 || j == 0)
        return 0;

    // If characters match and their
    // indices are different
    if (s[i - 1] == s[j - 1] && i != j)
    {
        return 1 + findLongestRepeatingSubsequence(i - 1, j - 1, s);
    }

    // Else make two recursive calls.
    return max(findLongestRepeatingSubsequence(i - 1, j, s), findLongestRepeatingSubsequence(i, j - 1, s));
}

int longestRepSubseq(string s)
{

    int n = s.length();
    return findLongestRepeatingSubsequence(n, n, s);
}

int main()
{

    string s = "axxxy";
    int res = longestRepSubseq(s);
    cout << res;

    return 0;
}
Java
class GFG {

    static int findLongestRepeatingSubsequence(int i, int j,
                                               String s)
    {
        // base case
        if (i == 0 || j == 0)
            return 0;

        // If characters match and their
        // indices are different
        if (s.charAt(i - 1) == s.charAt(j - 1) && i != j) {
            return 1
                + findLongestRepeatingSubsequence(i - 1,
                                                  j - 1, s);
        }

        // Else make two recursive calls.
        return Math.max(
            findLongestRepeatingSubsequence(i - 1, j, s),
            findLongestRepeatingSubsequence(i, j - 1, s));
    }

    static int longestRepSubseq(String s)
    {

        int n = s.length();
        return findLongestRepeatingSubsequence(n, n, s);
    }

    public static void main(String[] args)
    {

        String s = "axxxy";
        int res = longestRepSubseq(s);
        System.out.println(res);
    }
}
Python
def findLongestRepeatingSubsequence(i, j, s):

    # base case
    if i == 0 or j == 0:
        return 0

    # If characters match and their
    # indices are different
    if s[i - 1] == s[j - 1] and i != j:
        return 1 + findLongestRepeatingSubsequence(i - 1, j - 1, s)

    # Else make two recursive calls.
    return max(findLongestRepeatingSubsequence(i - 1, j, s),
               findLongestRepeatingSubsequence(i, j - 1, s))


def longestRepSubseq(s):
    n = len(s)
    return findLongestRepeatingSubsequence(n, n, s)


if __name__ == "__main__":
    s = "axxxy"
    res = longestRepSubseq(s)
    print(res)
C#
using System;

class GFG {

    static int findLongestRepeatingSubsequence(int i, int j,
                                               string s) {

        // base case
        if (i == 0 || j == 0)
            return 0;

        // If characters match and their
        // indices are different
        if (s[i - 1] == s[j - 1] && i != j) {
            return 1
                + findLongestRepeatingSubsequence(i - 1,
                                                  j - 1, s);
        }

        // Else make two recursive calls.
        return Math.Max(
            findLongestRepeatingSubsequence(i - 1, j, s),
            findLongestRepeatingSubsequence(i, j - 1, s));
    }

    static int longestRepSubseq(string s) {
        int n = s.Length;
        return findLongestRepeatingSubsequence(n, n, s);
    }

    static void Main(string[] args) {
        string s = "axxxy";
        int res = longestRepSubseq(s);
        Console.WriteLine(res);
    }
}
JavaScript
function findLongestRepeatingSubsequence(i, j, s) {

    // base case
    if (i === 0 || j === 0)
        return 0;

    // If characters match and their
    // indices are different
    if (s[i - 1] === s[j - 1] && i !== j) {
        return 1
               + findLongestRepeatingSubsequence(i - 1,
                                                 j - 1, s);
    }

    // Else make two recursive calls.
    return Math.max(
        findLongestRepeatingSubsequence(i - 1, j, s),
        findLongestRepeatingSubsequence(i, j - 1, s));
}

function longestRepSubseq(s) {
    const n = s.length;
    return findLongestRepeatingSubsequence(n, n, s);
}

//Driver Code
const s = "axxxy";
const res = longestRepSubseq(s);
console.log(res);

Output
2

[Better Approach] Using Top-Down DP (Memoization) – O(n ^ 2) Time and O(n ^ 2) Space

If we notice carefully, we can observe that the above recursive solution holds the following two properties of Dynamic Programming:

1. Optimal Substructure: The maximum length of repeating subsequence originating from i, j, i.e., longestRepeatingSubsequence(i, j), depends on the optimal solution of longestRepeatingSubsequence(i-1, j-1) if characters match and indices don't match. Otherwise, it depends on the maximum of longestRepeatingSubsequence(i-1, j) and longestRepeatingSubsequence(i, j-1).

2. Overlapping Subproblems: While applying a recursive approach in this problem, we notice that certain subproblems are computed multiple times.

  • There are two parameters, i and j that changes in the recursive solution. So we create a 2D array of size n*n for memoization.
  • We initialize this array as -1 to indicate nothing is computed initially.
  • Now we modify our recursive solution to first check if the value is -1, then only make recursive calls. This way, we avoid re-computations of the same subproblems.
C++
#include <bits/stdc++.h>
using namespace std;

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

    // base case
    if (i == 0 || j == 0)
        return 0;

    // If value is computed, return it.
    if (memo[i - 1][j - 1] != -1)
        return memo[i - 1][j - 1];

    // If characters match and their
    // indices are different
    if (s[i - 1] == s[j - 1] && i != j)
    {

        return memo[i - 1][j - 1] = 1 + findLongestRepeatingSubsequence(i - 1, j - 1, s, memo);
    }

    // Else make two recursive calls.
    return memo[i - 1][j - 1] = max(findLongestRepeatingSubsequence(i - 1, j, s, memo),
                                    findLongestRepeatingSubsequence(i, j - 1, s, memo));
}

int longestRepSubseq(string s) {

    int n = s.length();
    vector<vector<int>> memo(n, vector<int>(n, -1));
    return findLongestRepeatingSubsequence(n, n, s, memo);
}

int main() {

    string s = "axxxy";
    int res = longestRepSubseq(s);
    cout << res;

    return 0;
}
Java
class GFG {

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

        // base case
        if (i == 0 || j == 0)
            return 0;

        // If value is computed, return it.
        if (memo[i - 1][j - 1] != -1)
            return memo[i - 1][j - 1];

        // If characters match and their
        // indices are different
        if (s.charAt(i - 1) == s.charAt(j - 1) && i != j) {
            return memo[i - 1][j - 1]
                = 1
                  + findLongestRepeatingSubsequence(
                      i - 1, j - 1, s, memo);
        }

        // Else make two recursive calls.
        return memo[i - 1][j - 1]
            = Math.max(findLongestRepeatingSubsequence(
                           i - 1, j, s, memo),
                       findLongestRepeatingSubsequence(
                           i, j - 1, s, memo));
    }

    static int longestRepSubseq(String s) {
        int n = s.length();
        int[][] memo = new int[n][n];
        for (int[] row : memo) {
            java.util.Arrays.fill(row, -1);
        }
        return findLongestRepeatingSubsequence(n, n, s,
                                               memo);
    }

    public static void main(String[] args) {
        String s = "axxxy";
        int res = longestRepSubseq(s);
        System.out.println(res);
    }
}
Python
def findLongestRepeatingSubsequence(i, j, s, memo):

    # base case
    if i == 0 or j == 0:
        return 0

    # If value is computed, return it.
    if memo[i - 1][j - 1] != -1:
        return memo[i - 1][j - 1]

    # If characters match and their
    # indices are different
    if s[i - 1] == s[j - 1] and i != j:
        memo[i - 1][j - 1] = 1 + findLongestRepeatingSubsequence(
            i - 1, j - 1, s, memo
        )
        return memo[i - 1][j - 1]

    # Else make two recursive calls.
    memo[i - 1][j - 1] = max(
        findLongestRepeatingSubsequence(i - 1, j, s, memo),
        findLongestRepeatingSubsequence(i, j - 1, s, memo)
    )

    return memo[i - 1][j - 1]


def longestRepSubseq(s):

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

    return findLongestRepeatingSubsequence(n, n, s, memo)


if __name__ == "__main__":

    s = "axxxy"
    res = longestRepSubseq(s)
    print(res)
C#
using System;

class GFG {

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

        // base case
        if (i == 0 || j == 0)
            return 0;

        // If value is computed, return it.
        if (memo[i - 1, j - 1] != -1)
            return memo[i - 1, j - 1];

        // If characters match and their
        // indices are different
        if (s[i - 1] == s[j - 1] && i != j) {
            memo[i - 1, j - 1]
                = 1
                  + findLongestRepeatingSubsequence(
                      i - 1, j - 1, s, memo);
            return memo[i - 1, j - 1];
        }

        // Else make two recursive calls.
        memo[i - 1, j - 1]
            = Math.Max(findLongestRepeatingSubsequence(
                           i - 1, j, s, memo),
                       findLongestRepeatingSubsequence(
                           i, j - 1, s, memo));
        return memo[i - 1, j - 1];
    }

    static int longestRepSubseq(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;
            }
        }
        return findLongestRepeatingSubsequence(n, n, s,
                                               memo);
    }

    static void Main(string[] args) {

        string s = "axxxy";
        int res = longestRepSubseq(s);
        Console.WriteLine(res);
    }
}
JavaScript
function findLongestRepeatingSubsequence(i, j, s, memo)
{

    // base case
    if (i === 0 || j === 0)
        return 0;

    // If value is computed, return it.
    if (memo[i - 1][j - 1] !== -1)
        return memo[i - 1][j - 1];

    // If characters match and their
    // indices are different
    if (s[i - 1] === s[j - 1] && i !== j) {
        return memo[i - 1][j - 1]
               = 1
                 + findLongestRepeatingSubsequence(
                     i - 1, j - 1, s, memo);
    }

    // Else make two recursive calls.
    return memo[i - 1][j - 1]
           = Math.max(findLongestRepeatingSubsequence(
                          i - 1, j, s, memo),
                      findLongestRepeatingSubsequence(
                          i, j - 1, s, memo));
}

function longestRepSubseq(s)
{

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

// Driver Code
const s = "axxxy";
const res = longestRepSubseq(s);
console.log(res);

Output
2

[Expected Approach - 1] Using Bottom-Up DP (Tabulation) - O(n ^ 2) Time and O(n ^ 2) Space

The approach is similar to the previous one. just instead of breaking down the problem recursively, we iteratively build up the solution by calculating in bottom-up manner. The idea is to create a 2-D array. Then fill the values using dp[i][j] = 1 + dp[i-1][j-1] if characters match and indices don't match. Otherwise, set dp[i][j] = max(dp[i-1][j], dp[i][j-1]).

Working of Approach:

  • We use a 2D Dynamic Programming table dp, where dp[i, j] stores the length of the longest repeating subsequence using the first i and j characters.
  • If s[i-1] == s[j-1] and i != j, we include the character and set dp[i, j] = 1 + dp[i-1, j-1].
  • Otherwise, we take the maximum of excluding the current character from either side: max(dp[i-1, j], dp[i, j-1]).
  • The condition i != j ensures that the same character position is not matched with itself.
  • Finally, dp[n, n] contains the length of the Longest Repeating Subsequence.
C++
#include <iostream>
#include <vector>
using namespace std;

int longestRepSubseq(string& s) {
    int n = s.length();
    vector<vector<int>> dp(n+1, vector<int>(n+1, 0));
    
    for (int i=1; i<=n; i++) {
        for (int j=1; j<=n; j++) {
            
            // If char match and indices
            // are different
            if (s[i-1]==s[j-1] && i!=j) {
                dp[i][j] = 1 + dp[i-1][j-1];
            }
            else {
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
            }
        }
    }
    
    return dp[n][n];
}

int main() {
    string s = "axxxy";
    int res = longestRepSubseq(s);
    cout <<  res;

    return 0;
}
Java
class GFG {

    static int longestRepSubseq(String s) {
        int n = s.length();
        int[][] dp = new int[n + 1][n + 1];

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {

                // If char match and indices
                // are different
                if (s.charAt(i - 1) == s.charAt(j - 1) && i != j) {
                    dp[i][j] = 1 + dp[i - 1][j - 1];
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }

        return dp[n][n];
    }

    public static void main(String[] args) {
        String s = "axxxy";
        int res = longestRepSubseq(s);
        System.out.println(res);
    }
}
Python
def longestRepSubseq(s):
    n = len(s)
    dp = [[0 for _ in range(n + 1)] for _ in range(n + 1)]

    for i in range(1, n + 1):
        for j in range(1, n + 1):

            # If char match and indices
            # are different
            if s[i - 1] == s[j - 1] and i != j:
                dp[i][j] = 1 + dp[i - 1][j - 1]
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

    return dp[n][n]

if __name__ == "__main__":
    s = "axxxy"
    res = longestRepSubseq(s)
    print(res)
C#
using System;

class GFG {

    static int longestRepSubseq(string s) {
        int n = s.Length;
        int[,] dp = new int[n + 1, n + 1];

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {

                // If char match and indices
                // are different
                if (s[i - 1] == s[j - 1] && i != j) {
                    dp[i, j] = 1 + dp[i - 1, j - 1];
                } else {
                    dp[i, j] = Math.Max(dp[i - 1, j], dp[i, j - 1]);
                }
            }
        }

        return dp[n, n];
    }

    static void Main(string[] args) {
        string s = "axxxy";
        int res = longestRepSubseq(s);
        Console.WriteLine(res);
    }
}
JavaScript
function longestRepSubseq(s) {
    const n = s.length;
    const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(0));

    for (let i = 1; i <= n; i++) {
        for (let j = 1; j <= n; j++) {

            // If char match and indices
            // are different
            if (s[i - 1] === s[j - 1] && i !== j) {
                dp[i][j] = 1 + dp[i - 1][j - 1];
            } else {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }

    return dp[n][n];
}

//Driver Code
const s = "axxxy";
const res = longestRepSubseq(s);
console.log(res);

Output
2

[Expected Approach - 2] Using Space Optimized DP - O(n ^ 2) Time and O(n) Space

The idea is to store only the values required from the previous row. We can observe that for a given (i, j) its value is only dependent on (i-1, j-1) or (i-1, j) and (i, j-1).

Working of Approach:

  • We use 1D Dynamic Programming to find the Longest Repeating Subsequence by comparing the string with itself.
  • For every pair of indices (i, j), if s[i-1] == s[j-1] and i != j, we extend the subsequence using the diagonal value.
  • Otherwise, we take the maximum of the left (curr[j-1]) and top (curr[j]) values.
  • The match variable stores the previous diagonal value dp[i-1][j-1] to optimize space.
  • The final value curr[n] gives the length of the Longest Repeating Subsequence.
C++
#include <bits/stdc++.h>
using namespace std;

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

    // Create a 1D array for the current row
    vector<int> curr(n + 1, 0);

    // Variable to store dp[i-1][j-1] for each (i, j)
    // This helps to track the diagonal value from the previous iteration
    int match = 0;

    for (int i = 1; i <= n; i++) {

        // Reset match to 0 for the new row
        match = 0;

        for (int j = 1; j <= n; j++) {

            // Store the current cell value before updating
            int tmp = curr[j];

            // If characters match and indices are different
            if (s[i - 1] == s[j - 1] && i != j) {
                // Add 1 to the diagonal value
                curr[j] = 1 + match;
            }
            else {
                // Take the maximum value between left and top cells
                curr[j] = max(curr[j], curr[j - 1]);
            }
            // Update match to the previous cell value
            match = tmp;
        }
    }

    return curr[n];
}

int main() {

    string s = "axxxy";
    int res = longestRepSubseq(s);
    cout << res;
    return 0;
}
Java
class GFG {

    static int longestRepSubseq(String s) {
      
        // Get the length of the input string
        int n = s.length();

        // Create a 1D array to store the current row's
        // values
        int[] curr = new int[n + 1];

        // Variable to store the value of dp[i-1][j-1]
        // (diagonal element)
        int match;

        // Iterate over all characters of the string for row
        // index
        for (int i = 1; i <= n; i++) {

            // Reset match for each new row
            match = 0;

            // Iterate over all characters of the string for
            // column index
            for (int j = 1; j <= n; j++) {

                // Temporarily store the current cell value
                // before updating it
                int tmp = curr[j];

                // If characters match and indices are
                // different, update with diagonal value + 1
                if (s.charAt(i - 1) == s.charAt(j - 1)
                    && i != j) {
                    curr[j] = 1 + match;
                }
                else {
                    // Otherwise, take the maximum of the
                    // left and top cells
                    curr[j]
                        = Math.max(curr[j], curr[j - 1]);
                }

                // Update match to the previously stored
                // value of curr[j]
                match = tmp;
            }
        }

        // Return the value in the last cell, which contains
        // the length of the longest repeating subsequence
        return curr[n];
    }

    public static void main(String[] args) {
        
        String s = "axxxy";
        int res = longestRepSubseq(s);
        System.out.println(res);
    }
}
Python
def longestRepSubseq(s):

    # Get the length of the input string
    n = len(s)

    # Create a 1D array to store the current row's values
    curr = [0] * (n + 1)

    # Variable to store the value of dp[i-1][j-1] (diagonal element)
    match = 0

    # Iterate over all characters of the string for row index
    for i in range(1, n + 1):

        # Reset match for each new row
        match = 0

        # Iterate over all characters of the string for column index
        for j in range(1, n + 1):

            # Temporarily store the current cell value before updating it
            tmp = curr[j]

            # If characters match and indices are different,
            # update with diagonal value + 1
            if s[i - 1] == s[j - 1] and i != j:
                curr[j] = 1 + match
            else:
                # Otherwise, take the maximum of the left and top cells
                curr[j] = max(curr[j], curr[j - 1])

            # Update match to the previously stored value of curr[j]
            match = tmp

    # Return the value in the last cell, which contains the length of
    # the longest repeating subsequence
    return curr[n]


if __name__ == "__main__":
    s = "axxxy"
    res = longestRepSubseq(s)
    print(res)
C#
using System;

class GFG {
    static int longestRepSubseq(string s) {
      
        // Get the length of the input string
        int n = s.Length;

        // Create a 1D array to store the current row's
        // values
        int[] curr = new int[n + 1];

        // Variable to store the value of dp[i-1][j-1]
        // (diagonal element)
        int match = 0;

        // Iterate over all characters of the string for row
        // index
        for (int i = 1; i <= n; i++) {
            // Reset match for each new row
            match = 0;

            // Iterate over all characters of the string for
            // column index
            for (int j = 1; j <= n; j++) {
                // Temporarily store the current cell value
                // before updating it
                int tmp = curr[j];

                // If characters match and indices are
                // different, update with diagonal value + 1
                if (s[i - 1] == s[j - 1] && i != j) {
                    curr[j] = 1 + match;
                }
                else {
                    // Otherwise, take the maximum of the
                    // left and top cells
                    curr[j]
                        = Math.Max(curr[j], curr[j - 1]);
                }

                // Update match to the previously stored
                // value of curr[j]
                match = tmp;
            }
        }

        // Return the value in the last cell, which contains
        // the length of the longest repeating subsequence
        return curr[n];
    }

    static void Main(string[] args) {
        string s = "axxxy";
        int res = longestRepSubseq(s);
        Console.WriteLine(res);
    }
}
JavaScript
function longestRepSubseq(s)
{
    let n = s.length;
    // Create a 1D array for the current row
    let curr = Array(n + 1).fill(0);
    // Variable to store dp[i-1][j-1] for each (i, j)
    // This helps to track the diagonal value from the
    // previous iteration
    let match = 0;
    for (let i = 1; i <= n; i++) {
        // Reset match to 0 for the new row
        match = 0;
        for (let j = 1; j <= n; j++) {
            // Store the current cell value before updating
            let tmp = curr[j];
            // If characters match and indices are different
            if (s[i - 1] === s[j - 1] && i !== j) {
                // Add 1 to the diagonal value
                curr[j] = 1 + match;
            }
            else {
                // Take the maximum value between left and
                // top cells
                curr[j] = Math.max(curr[j], curr[j - 1]);
            }
            // Update match to the previous cell value
            match = tmp;
        }
    }
    return curr[n];
}

// Driver Code
let s = "axxxy";
let res = longestRepSubseq(s);
console.log(res);

Output
2
Comment