Printing Longest Common Subsequence (original) (raw)

Last Updated : 23 Jul, 2025

Given two sequences, print the longest subsequence present in both of them.

**Examples:

We have discussed Longest Common Subsequence (LCS) problem in a previous post. The function discussed there was mainly to find the length of LCS. To find length of LCS, a 2D table L[][] was constructed. In this post, the function to construct and print LCS is discussed.

Following is detailed algorithm to print the LCS. It uses the same 2D table L[][].

  1. Construct L[m+1][n+1] using the steps discussed in previous post.
  2. The value L[m][n] contains length of LCS. Create a character array lcs[] of length equal to the length of lcs plus 1 (one extra to store \0).
  3. Traverse the 2D array starting from L[m][n]. Do following for every cell L[i][j]
    • If characters (in X and Y) corresponding to L[i][j] are same (Or X[i-1] == Y[j-1]), then include this character as part of LCS.
    • Else compare values of L[i-1][j] and L[i][j-1] and go in direction of greater value.

The following table (taken from Wiki) shows steps (highlighted) followed by the above algorithm.

| | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | | | --- | - | ------- | ------- | - | ------- | ------- | - | - | ------- | | Ø | M | Z | J | A | W | X | U | | | | 0 | Ø | **0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | 1 | X | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | | 2 | M | 0 | **1 | 1 | 1 | 1 | 1 | 1 | 1 | | 3 | J | 0 | 1 | 1 | **2 | 2 | 2 | 2 | 2 | | 4 | Y | 0 | 1 | 1 | 2 | 2 | 2 | 2 | 2 | | 5 | A | 0 | 1 | 1 | 2 | **3 | 3 | 3 | 3 | | 6 | U | 0 | 1 | 1 | 2 | 3 | 3 | 3 | **4 | | 7 | Z | 0 | 1 | 2 | 2 | 3 | 3 | 3 | 4 |

Following is the implementation of the above approach.

C++14 `

/* Dynamic Programming implementation of LCS problem */ #include #include #include using namespace std;

/* Returns length of LCS for X[0..m-1], Y[0..n-1] / void lcs(char X, char* Y, int m, int n) { int L[m + 1][n + 1];

/* Following steps build L[m+1][n+1] in bottom up
  fashion. Note that L[i][j] contains length of LCS of
  X[0..i-1] and Y[0..j-1] */
for (int i = 0; i <= m; i++) {
    for (int j = 0; j <= n; j++) {
        if (i == 0 || j == 0)
            L[i][j] = 0;
        else if (X[i - 1] == Y[j - 1])
            L[i][j] = L[i - 1][j - 1] + 1;
        else
            L[i][j] = max(L[i - 1][j], L[i][j - 1]);
    }
}

// Following code is used to print LCS
int index = L[m][n];

// Create a character array to store the lcs string
char lcs[index + 1];
lcs[index] = '\0'; // Set the terminating character

// Start from the right-most-bottom-most corner and
// one by one store characters in lcs[]
int i = m, j = n;
while (i > 0 && j > 0) {
    // If current character in X[] and Y are same, then
    // current character is part of LCS
    if (X[i - 1] == Y[j - 1]) {
        lcs[index - 1]
            = X[i - 1]; // Put current character in result
        i--;
        j--;
        index--; // reduce values of i, j and index
    }

    // If not same, then find the larger of two and
    // go in the direction of larger value
    else if (L[i - 1][j] > L[i][j - 1])
        i--;
    else
        j--;
}

// Print the lcs
cout << "LCS of " << X << " and " << Y << " is " << lcs;

}

/* Driver program to test above function */ int main() { char X[] = "AGGTAB"; char Y[] = "GXTXAYB"; int m = strlen(X); int n = strlen(Y); lcs(X, Y, m, n); return 0; }

Java

// Dynamic Programming implementation of LCS problem in Java import java.io.*;

class LongestCommonSubsequence { // Returns length of LCS for X[0..m-1], Y[0..n-1] static void lcs(String X, String Y, int m, int n) { int[][] L = new int[m + 1][n + 1];

    // Following steps build L[m+1][n+1] in bottom up
    // fashion. Note that L[i][j] contains length of LCS
    // of X[0..i-1] and Y[0..j-1]
    for (int i = 0; i <= m; i++) {
        for (int j = 0; j <= n; j++) {
            if (i == 0 || j == 0)
                L[i][j] = 0;
            else if (X.charAt(i - 1) == Y.charAt(j - 1))
                L[i][j] = L[i - 1][j - 1] + 1;
            else
                L[i][j] = Math.max(L[i - 1][j],
                                   L[i][j - 1]);
        }
    }

    // Following code is used to print LCS
    int index = L[m][n];
    int temp = index;

    // Create a character array to store the lcs string
    char[] lcs = new char[index + 1];
    lcs[index]
        = '\u0000'; // Set the terminating character

    // Start from the right-most-bottom-most corner and
    // one by one store characters in lcs[]
    int i = m;
    int j = n;
    while (i > 0 && j > 0) {
        // If current character in X[] and Y are same,
        // then current character is part of LCS
        if (X.charAt(i - 1) == Y.charAt(j - 1)) {
            // Put current character in result
            lcs[index - 1] = X.charAt(i - 1);

            // reduce values of i, j and index
            i--;
            j--;
            index--;
        }

        // If not same, then find the larger of two and
        // go in the direction of larger value
        else if (L[i - 1][j] > L[i][j - 1])
            i--;
        else
            j--;
    }

    // Print the lcs
    System.out.print("LCS of " + X + " and " + Y
                     + " is ");
    for (int k = 0; k <= temp; k++)
        System.out.print(lcs[k]);
}

// driver program
public static void main(String[] args)
{
    String X = "AGGTAB";
    String Y = "GXTXAYB";
    int m = X.length();
    int n = Y.length();
    lcs(X, Y, m, n);
}

}

// Contributed by Pramod Kumar

Python3

Dynamic programming implementation of LCS problem

Returns length of LCS for X[0..m-1], Y[0..n-1]

def lcs(X, Y, m, n): L = [[0 for i in range(n+1)] for j in range(m+1)]

# Following steps build L[m+1][n+1] in bottom up fashion. Note
# that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1]
for i in range(m+1):
    for j in range(n+1):
        if i == 0 or j == 0:
            L[i][j] = 0
        elif X[i-1] == Y[j-1]:
            L[i][j] = L[i-1][j-1] + 1
        else:
            L[i][j] = max(L[i-1][j], L[i][j-1])

    # Create a string variable to store the lcs string
lcs = ""

# Start from the right-most-bottom-most corner and
# one by one store characters in lcs[]
i = m
j = n
while i > 0 and j > 0:

    # If current character in X[] and Y are same, then
    # current character is part of LCS
    if X[i-1] == Y[j-1]:
        lcs += X[i-1]
        i -= 1
        j -= 1

    # If not same, then find the larger of two and
    # go in the direction of larger value
    elif L[i-1][j] > L[i][j-1]:
        i -= 1
        
    else:
        j -= 1

# We traversed the table in reverse order
# LCS is the reverse of what we got
lcs = lcs[::-1]
print("LCS of " + X + " and " + Y + " is " + lcs)

Driver program

X = "AGGTAB" Y = "GXTXAYB" m = len(X) n = len(Y) lcs(X, Y, m, n)

This code is contributed by AMAN ASATI

C#

// Dynamic Programming implementation // of LCS problem in C# using System;

class GFG { // Returns length of LCS for X[0..m-1], Y[0..n-1] static void lcs(String X, String Y, int m, int n) { int[, ] L = new int[m + 1, n + 1];

    // Following steps build L[m+1][n+1] in
    // bottom up fashion. Note that L[i][j]
    // contains length of LCS of X[0..i-1]
    // and Y[0..j-1]
    for (int i = 0; i <= m; i++) {
        for (int j = 0; j <= n; j++) {
            if (i == 0 || j == 0)
                L[i, j] = 0;
            else if (X[i - 1] == Y[j - 1])
                L[i, j] = L[i - 1, j - 1] + 1;
            else
                L[i, j] = Math.Max(L[i - 1, j],
                                   L[i, j - 1]);
        }
    }

    // Following code is used to print LCS
    int index = L[m, n];
    int temp = index;

    // Create a character array
    // to store the lcs string
    char[] lcs = new char[index + 1];

    // Set the terminating character
    lcs[index] = '\0';

    // Start from the right-most-bottom-most corner
    // and one by one store characters in lcs[]
    int k = m, l = n;
    while (k > 0 && l > 0) {
        // If current character in X[] and Y
        // are same, then current character
        // is part of LCS
        if (X[k - 1] == Y[l - 1]) {
            // Put current character in result
            lcs[index - 1] = X[k - 1];

            // reduce values of i, j and index
            k--;
            l--;
            index--;
        }

        // If not same, then find the larger of two and
        // go in the direction of larger value
        else if (L[k - 1, l] > L[k, l - 1])
            k--;
        else
            l--;
    }

    // Print the lcs
    Console.Write("LCS of " + X + " and " + Y + " is ");
    for (int q = 0; q <= temp; q++)
        Console.Write(lcs[q]);
}

// Driver program
public static void Main()
{
    String X = "AGGTAB";
    String Y = "GXTXAYB";
    int m = X.Length;
    int n = Y.Length;
    lcs(X, Y, m, n);
}

}

// This code is contributed by Sam007

JavaScript

PHP

X,X, X,Y, m,m, m,n ) { L=arrayfill(0,L = array_fill(0, L=arrayfill(0,m + 1, array_fill(0, $n + 1, NULL)); /* Following steps build L[m+1][n+1] in bottom up fashion. Note that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1] */ for ($i = 0; i<=i <= i<=m; $i++) { for ($j = 0; j<=j <= j<=n; $j++) { if ($i == 0 || $j == 0) L[L[L[i][$j] = 0; else if ($X[$i - 1] == Y[Y[Y[j - 1]) L[L[L[i][$j] = L[L[L[i - 1][$j - 1] + 1; else L[L[L[i][$j] = max($L[$i - 1][$j], L[L[L[i][$j - 1]); } } // Following code is used to print LCS index=index = index=L[$m][$n]; temp=temp = temp=index; // Create a character array to store the lcs string lcs=arrayfill(0,lcs = array_fill(0, lcs=arrayfill(0,index + 1, NULL); lcs[lcs[lcs[index] = ''; // Set the terminating character // Start from the right-most-bottom-most corner // and one by one store characters in lcs[] i=i = i=m; j=j = j=n; while ($i > 0 && $j > 0) { // If current character in X[] and Y are same, // then current character is part of LCS if ($X[$i - 1] == Y[Y[Y[j - 1]) { // Put current character in result lcs[lcs[lcs[index - 1] = X[X[X[i - 1]; $i--; $j--; $index--; // reduce values of i, j and index } // If not same, then find the larger of two // and go in the direction of larger value else if ($L[$i - 1][$j] > L[L[L[i][$j - 1]) $i--; else $j--; } // Print the lcs echo "LCS of " . X."and".X . " and " . X."and".Y . " is "; for($k = 0; k<k < k<temp; $k++) echo lcs[lcs[lcs[k]; } // Driver Code $X = "AGGTAB"; $Y = "GXTXAYB"; m=strlen(m = strlen(m=strlen(X); n=strlen(n = strlen(n=strlen(Y); lcs($X, Y,Y, Y,m, $n); // This code is contributed by ita_c ?>

`

Output

LCS of AGGTAB and GXTXAYB is GTAB

**Time Complexity: O(m*n)
**Auxiliary Space: O(m*n)

Top-down approach for printing Longest Common Subsequence:

Follow the steps below for the implementation:

Here is the implementation of the above recursive approach.

C++ `

#include #include #include using namespace std; using mpsss = map<pair<string, string>, string>; using mpssi = map<pair<string, string>, int>; using ss = pair<string, string>;

mpsss dp;

// For keep track of visited subproblem or not (0 = not // visited, 1 = visited) mpssi vs;

// utility function to reverse a string, we need it because // our top-down approach return a reversed solution string reverse(string str) { string ans = str; int u = 0; int v = ans.length() - 1; while (u < v) { swap(ans[u], ans[v]); u++; v--; } return ans; }

// utility function that compares two strings and return the // longer in size. string max_str(string a, string b) { if (a.length() > b.length()) return a; else return b; }

string LCS_core(string a, string b) {

// size of string a
int n_a = a.length();

// size of string b
int n_b = b.length();

// Base case
if (n_a == 0 || n_b == 0)
    return "";

// dp index to access the dp structure
ss dp_i = make_pair(a, b);

// ans points to the memory location in the dp
// structure in which the solution string will be stored
string& ans = dp[dp_i];

// if visited return solution from memory.
if (vs[dp_i] == 1)
    return dp[dp_i];

// if not visited, set the visit value to be one
// (meaning its now visited)
else
    vs[dp_i] = 1;

// if the last two character match
if (a[n_a - 1] == b[n_b - 1]) {

    // Add this character to the solution string
    ans += a[n_a - 1];

    // Erase last character from a
    a.erase(n_a - 1, 1);

    // Erase last character from b
    b.erase(n_b - 1, 1);

    // add to the solution string the value of
    // LCS_core(a, b) (the remaining strings after
    // deleting last characters)
    ans += LCS_core(a, b);
    return ans;
}

// Return longest string
ans += max_str(LCS_core(a.substr(0, n_a - 1), b),
               LCS_core(a, b.substr(0, n_b - 1)));
return ans;

}

string LCS(string a, string b) { ;

// Reverse obtained result
return reverse(LCS_core(a, b));

}

int main() { string a = "AGGTAB"; string b = "GXTXAYB"; cout << LCS(a, b); return 0; }

Java

import java.util.HashMap; import java.util.Map;

class Main { public static void main(String[] args) { String a = "AGGTAB"; String b = "GXTXAYB"; System.out.println(LCS(a, b)); }

private static Map<String, Map<String, String>> dp = new HashMap<>();
private static Map<String, Map<String, Integer>> vs = new HashMap<>();

private static String reverse(String str) {
    String ans = "";
    for (int i = str.length() - 1; i >= 0; i--) {
        ans += str.charAt(i);
    }
    return ans;
}

private static String max_str(String a, String b) {
    return a.length() > b.length() ? a : b;
}

private static String LCS_core(String a, String b) {
    if (a.isEmpty() || b.isEmpty()) {
        return "";
    }

    if (vs.containsKey(a) && vs.get(a).containsKey(b)) {
        return dp.get(a).get(b);
    }

    String ans = "";
    if (a.charAt(a.length() - 1) == b.charAt(b.length() - 1)) {
        ans += a.charAt(a.length() - 1);
        a = a.substring(0, a.length() - 1);
        b = b.substring(0, b.length() - 1);
        ans += LCS_core(a, b);
    } else {
        ans += max_str(LCS_core(a.substring(0, a.length() - 1), b),
                       LCS_core(a, b.substring(0, b.length() - 1)));
    }
    if (!dp.containsKey(a)) {
        dp.put(a, new HashMap<>());
    }
    if (!vs.containsKey(a)) {
        vs.put(a, new HashMap<>());
    }
    dp.get(a).put(b, ans);
    vs.get(a).put(b, 1);
    return ans;
}

private static String LCS(String a, String b) {
    return reverse(LCS_core(a, b));
}

}

// This code is contributed by Susobhan Akhuli

Python3

from typing import Dict, Tuple

Initialize an empty dictionary to store the solutions of subproblems

dp: Dict[Tuple[str, str], str] = {}

Initialize an empty dictionary to keep track of visited subproblems

vs: Dict[Tuple[str, str], int] = {}

Utility function to reverse a string, we need it because our top-down approach

return a reversed solution

def reverse(s: str) -> str: ans = list(s) u, v = 0, len(ans) - 1 while u < v: ans[u], ans[v] = ans[v], ans[u] #swap operation u += 1 v -= 1 return "".join(ans)

Utility function that compares two strings and return the longer in size.

def max_str(a: str, b: str) -> str: return a if len(a) > len(b) else b

Recursive function that takes two strings as input, and returns the LCS of them

def LCS_core(a: str, b: str) -> str: # Base case if not a or not b: return "" # dp index to access the dp structure dp_i = (a, b)

# if visited return solution from memory
if dp_i in vs:
    return dp[dp_i]
else:
    vs[dp_i] = 1

# if the last two character match
if a[-1] == b[-1]:
    ans = a[-1] + LCS_core(a[:-1], b[:-1])
    dp[dp_i] = ans
    return ans

# Return longest string
ans = max_str(LCS_core(a[:-1], b), LCS_core(a, b[:-1]))
dp[dp_i] = ans
return ans

Final wrapper function to call the recursive function and reverse the result

def LCS(a: str, b: str) -> str: return reverse(LCS_core(a, b))

a = "AGGTAB" b = "GXTXAYB" print(LCS(a, b))

This code is contributed by Shivam Tiwari

C#

using System; using System.Collections.Generic namespace LongestCommonSubsequence {

public class GFG{

    static void Main(string[] args)
    {
        string a = "AGGTAB";
        string b = "GXTXAYB";
        Console.WriteLine(LCS(a, b));
    }

    // Utility function to reverse a string
    static string Reverse(string str)
    {
        char[] charArray = str.ToCharArray();
        Array.Reverse(charArray);
        return new string(charArray);
    }

    // Utility function to return the larger string
    static string MaxStr(string a, string b)
    {
        return a.Length > b.Length ? a : b;
    }

    // Main function that returns the LCS
    static string LCS_Core(string a, string b, Dictionary<string, string> dp, Dictionary<string, int> vs)
    {
        int n_a = a.Length;
        int n_b = b.Length;

        // Base case
        if (n_a == 0 || n_b == 0)
        {
            return "";
        }

        // dp index to access the dp dictionary
        string dp_i = a + "," + b;

        // ans points to the memory location in the dp
        // dictionary in which the solution string will be stored
        string ans;
        if (dp.TryGetValue(dp_i, out ans))
        {
            // If visited return solution from memory
            return ans;
        }

        // If not visited, set the visit value to be one
        // (meaning it's now visited)
        vs[dp_i] = 1;

        // If the last two characters match
        if (a[n_a - 1] == b[n_b - 1])
        {
            // Add this character to the solution string
            ans = a[n_a - 1] + LCS_Core(a.Substring(0, n_a - 1), b.Substring(0, n_b - 1), dp, vs);
            dp[dp_i] = ans;
            return ans;
        }

        // Return longest string
        ans = MaxStr(LCS_Core(a.Substring(0, n_a - 1), b, dp, vs), LCS_Core(a, b.Substring(0, n_b - 1), dp, vs));
        dp[dp_i] = ans;
        return ans;
    }

    static string LCS(string a, string b)
    {
        Dictionary<string, string> dp = new Dictionary<string, string>();
        Dictionary<string, int> vs = new Dictionary<string, int>();

        string ans = LCS_Core(a, b, dp, vs);

        // Reverse the obtained result
        return Reverse(ans);
    }
}

}

` JavaScript ``

// Initialize an empty dictionary to store the solutions of subproblems let dp = {}; // Initialize an empty dictionary to keep track of visited subproblems let vs = {};

// Utility function to reverse a string, we need it because our top-down approach // return a reversed solution function reverse(s) { let ans = s.split(""); let u = 0; let v = ans.length - 1; while (u < v) { [ans[u], ans[v]] = [ans[v], ans[u]]; // swap operation u++; v--; } return ans.join(""); }

// Utility function that compares two strings and return the longer in size. function maxStr(a, b) { return a.length > b.length ? a : b; }

// Recursive function that takes two strings as input, // and returns the LCS of them function LCS_core(a, b) { // Base case if (!a || !b) return "";

// dp index to access the dp structure
let dp_i = `${a},${b}`;

//  if visited return solution from memory
if (dp_i in vs) return dp[dp_i];
else vs[dp_i] = 1;

// if the last two character match
if (a[a.length - 1] === b[b.length - 1]) {
    let ans = a[a.length - 1] + LCS_core(a.slice(0, -1), b.slice(0, -1));
    dp[dp_i] = ans;
    return ans;
}

// Return longest string
let ans = maxStr(LCS_core(a.slice(0, -1), b), LCS_core(a, b.slice(0, -1)));
dp[dp_i] = ans;
return ans;

}

// Final wrapper function to call the // recursive function and reverse the result function LCS(a, b) { return reverse(LCS_core(a, b)); }

// Driver Code const a = "AGGTAB"; const b = "GXTXAYB"; console.log(LCS(a, b));

``

Time complexity: O(m*n) where m is the length of the first string and n is the length of the second string. This is because, for each character in both strings, we need to check whether they are equal and then recursively call the LCS_core() function.

**Auxiliary space: O(m*n) as well. This is because we are using a map structure to keep track of the visited subproblems and the result of each subproblem. This structure is having a size of O(m*n).