Longest Common Subsequence (LCS)

Last Updated : 13 Apr, 2026

Given two strings, s1 and s2, find the length of the Longest Common Subsequence. If there is no common subsequence, return 0. A subsequence is a string generated from the original string by deleting 0 or more characters, without changing the relative order of the remaining characters.

For example, subsequences of "ABC" are "", "A", "B", "C", "AB", "AC", "BC" and "ABC". In general, a string of length n has 2n subsequences.

Examples:

Input: s1 = "ABC", s2 = "ACD"
Output: 2
Explanation: The longest subsequence which is present in both strings is "AC".

Input: s1 = "AGGTAB", s2 = "GXTXAYB"
Output: 4
Explanation: The longest common subsequence is "GTAB".

Input: s1 = "ABC", s2 = "CBA"
Output: 1
Explanation: There are three longest common subsequences of length 1, "A", "B" and "C".

Try It Yourself
redirect icon

[Naive Approach] Using Recursion - O(2 ^ min(m, n)) Time and O(min(m, n)) Space

The idea is to compare the last characters of s1 and s2. While comparing the strings s1 and s2 two cases arise:

  • Match : Make the recursion call for the remaining strings (strings of lengths m-1 and n-1) and add 1 to result.
  • Do not Match : Make two recursive calls. First for lengths m-1 and n, and second for m and n-1. Take the maximum of two results.
  • Base case : If any of the strings become empty, we return 0.

For example, consider the input strings s1 = "ABX" and s2 = "ACX".

LCS("ABX", "ACX") = 1 + LCS("AB", "AC") [Last Characters Match]

LCS("AB", "AC") = max( LCS("A", "AC") , LCS("AB", "A") ) [Last Characters Do Not Match]

LCS("A", "AC") = max( LCS("", "AC") , LCS("A", "A") ) = max(0, 1 + LCS("", "")) = 1

LCS("AB", "A") = max( LCS("A", "A") , LCS("AB", "") ) = max( 1 + LCS("", "", 0)) = 1

So overall result is 1 + 1 = 2

C++
#include <iostream>   
#include <string>     
#include <algorithm> 
using namespace std;

// Returns length of LCS for s1[0..m-1], s2[0..n-1]
int lcsRec(string &s1, string &s2,int m,int n) {
    
    // Base case: If either string is empty, the length of LCS is 0
    if (m == 0 || n == 0)
        return 0;

    // If the last characters of both substrings match
    if (s1[m - 1] == s2[n - 1])
      
        // Include this character in LCS and recur for remaining substrings
        return 1 + lcsRec(s1, s2, m - 1, n - 1);

    else
        // If the last characters do not match
        // Recur for two cases:
        // 1. Exclude the last character of s1 
        // 2. Exclude the last character of s2 
        // Take the maximum of these two recursive calls
        return max(lcsRec(s1, s2, m, n - 1), lcsRec(s1, s2, m - 1, n));
}
int lcs(string &s1,string &s2){
    
    int m = s1.size(), n = s2.size();
    return lcsRec(s1,s2,m,n);
}

int main() {
    string s1 = "AGGTAB";
    string s2 = "GXTXAYB";
    int m = s1.size();
    int n = s2.size();

    cout << lcs(s1, s2) << endl;

    return 0;
}
C
#include <stdio.h>
#include <string.h>

int max(int x, int y) {
  	return x > y ? x : y; 
}

// Returns length of LCS for s1[0..m-1], s2[0..n-1]
int lcsRec(char s1[], char s2[], int m, int n) {

    // Base case: If either string is empty, the length of LCS is 0
    if (m == 0 || n == 0)
        return 0;

    // If the last characters of both substrings match
    if (s1[m - 1] == s2[n - 1])

        // Include this character in LCS and recur for remaining substrings
        return 1 + lcsRec(s1, s2, m - 1, n - 1);

    else
        // If the last characters do not match
        // Recur for two cases:
        // 1. Exclude the last character of S1 
        // 2. Exclude the last character of S2 
        // Take the maximum of these two recursive calls
        return max(lcsRec(s1, s2, m, n - 1), lcsRec(s1, s2, m - 1, n));
}
int lcs(char s1[],char s2[]){
    int m = strlen(s1);
    int n = strlen(s2);
    
    return lcsRec(s1,s2,m,n);
}

int main() {
    char s1[] = "AGGTAB";
    char s2[] = "GXTXAYB";
    printf("%d\n", lcs(s1, s2));
    return 0;
}
Java
class GfG {

    // Returns length of LCS for s1[0..m-1], s2[0..n-1]
    static int lcsRec(String s1, String s2, int m, int n) {

        // Base case: If either string is empty, the length of LCS is 0
        if (m == 0 || n == 0)
            return 0;

        // If the last characters of both substrings match
        if (s1.charAt(m - 1) == s2.charAt(n - 1))

            // Include this character in LCS and recur for remaining substrings
            return 1 + lcsRec(s1, s2, m - 1, n - 1);

        else
            // If the last characters do not match
            // Recur for two cases:
            // 1. Exclude the last character of S1 
            // 2. Exclude the last character of S2 
            // Take the maximum of these two recursive calls
            return Math.max(lcsRec(s1, s2, m, n - 1), lcsRec(s1, s2, m - 1, n));
    }
    static int lcs(String s1,String s2){
        int m = s1.length(), n = s2.length();
        return lcsRec(s1,s2,m,n);
    }
    public static void main(String[] args) {
        String s1 = "AGGTAB";
        String s2 = "GXTXAYB";
        System.out.println(lcs(s1, s2));
    }
}
Python
def lcsRec(s1, s2, m, n):
  
    # Base case: If either string is empty, the length of LCS is 0
    if m == 0 or n == 0:
        return 0

    # If the last characters of both substrings match
    if s1[m - 1] == s2[n - 1]:

        # Include this character in LCS and recur for remaining substrings
        return 1 + lcsRec(s1, s2, m - 1, n - 1)

    else:
        # If the last characters do not match
        # Recur for two cases:
        # 1. Exclude the last character of S1 
        # 2. Exclude the last character of S2 
        # Take the maximum of these two recursive calls
        return max(lcsRec(s1, s2, m, n - 1), lcsRec(s1, s2, m - 1, n))

def lcs(s1,s2):
    m = len(s1)
    n = len(s2)
    return lcsRec(s1,s2,m,n)

if __name__ == "__main__":
    s1 = "AGGTAB"
    s2 = "GXTXAYB"
    print(lcs(s1, s2))
C#
using System;

class GfG {

    // Returns length of LCS for s1[0..m-1], s2[0..n-1]
    static int lcsRec(string s1, string s2, int m, int n) {

        // Base case: If either string is empty, the length of LCS is 0
        if (m == 0 || n == 0)
            return 0;

        // If the last characters of both substrings match
        if (s1[m - 1] == s2[n - 1])

            // Include this character in LCS and recur for remaining substrings
            return 1 + lcsRec(s1, s2, m - 1, n - 1);

        else
            // If the last characters do not match
            // Recur for two cases:
            // 1. Exclude the last character of S1 
            // 2. Exclude the last character of S2 
            // Take the maximum of these two recursive calls
            return Math.Max(lcsRec(s1, s2, m, n - 1), lcsRec(s1, s2, m - 1, n));
    }
    static int lcs(string s1,string s2){
        int m = s1.Length , n = s2.Length; 
        return lcsRec(s1,s2,m,n);
    }
    static void Main() {
        string s1 = "AGGTAB";
        string s2 = "GXTXAYB";
        Console.WriteLine(lcs(s1, s2));
    }
}
JavaScript
function lcsRec(s1, s2, m, n) {
  
    // Base case: If either string is empty, the length of LCS is 0
    if (m === 0 || n === 0)
        return 0;

    // If the last characters of both substrings match
    if (s1[m - 1] === s2[n - 1])

        // Include this character in LCS and recur for remaining substrings
        return 1 + lcsRec(s1, s2, m - 1, n - 1);

    else
        return Math.max(lcsRec(s1, s2, m, n - 1), lcsRec(s1, s2, m - 1, n));
}
function lcs(s1,s2){
    
    let m = s1.length;
    let n = s2.length;
    return lcsRec(s1,s2,m,n);
}

// driver code
let s1 = "AGGTAB";
let s2 = "GXTXAYB";
let m = s1.length;
let n = s2.length;

console.log(lcs(s1, s2, m, n));

Output
4

[Better Approach] Using Memoization (Top Down DP) - O(m * n) Time and O(m * n) Space

If we use the above recursive approach for strings "AXYT" and "AYZX", we will get a partial recursion tree as shown below. Here we can see that the subproblem L("AXY", "AYZ") is being calculated more than once. If the total tree is considered there will be several such overlapping subproblems. Hence we can optimize it either using memoization or tabulation.

  • There are two parameters that change in the recursive solution and these parameters go from 0 to m and 0 to n. So we create a 2D array of size (m+1) x (n+1).
  • We initialize this array as -1 to indicate nothing is computed initially.
  • Now we modify our recursive solution to first do a lookup in this table and if the value is -1, then only make recursive calls. This way we avoid re-computations of the same subproblems.
Longest-Common-Subsequence
Overlapping Subproblems in Longest Common Subsequence
C++
#include <iostream>   
#include <string>   
#include <algorithm>  
using namespace std;

// Returns length of LCS for s1[0..m-1], s2[0..n-1]
int lcsRec(string &s1, string &s2, int m, int n, vector<vector<int>> &memo) {

    // Base Case
    if (m == 0 || n == 0)
        return 0;

    // Already exists in the memo table
    if (memo[m][n] != -1)
        return memo[m][n];

    // Match
    if (s1[m - 1] == s2[n - 1])
        return memo[m][n] = 1 + lcsRec(s1, s2, m - 1, n - 1, memo);

    // Do not match
    return memo[m][n] = max(lcsRec(s1, s2, m, n - 1, memo), lcsRec(s1, s2, m - 1, n, memo));
}
int lcs(string &s1,string &s2){
    int m = s1.length();
    int n = s2.length();
    vector<vector<int>> memo(m + 1, vector<int>(n + 1, -1));
    return lcsRec(s1, s2, m, n, memo);
}

int main() {
    string s1 = "AGGTAB";
    string s2 = "GXTXAYB";
    cout << lcs(s1, s2) << endl;
    return 0;
}
C
#include <stdio.h>
#include <string.h>

// Define a maximum size for the strings
#define MAX 1000

// Function to find the maximum of two integers
int max(int a, int b) {
    return (a > b) ? a : b;
}

// Returns length of LCS for s1[0..m-1], s2[0..n-1]
int lcsRec(const char *s1, const char *s2, int m, int n, int memo[MAX][MAX]) {
  
    // Base Case
    if (m == 0 || n == 0) {
        return 0;
    }

    // Already exists in the memo table
    if (memo[m][n] != -1) {
        return memo[m][n];
    }

    // Match
    if (s1[m - 1] == s2[n - 1]) {
        return memo[m][n] = 1 + lcsRec(s1, s2, m - 1, n - 1, memo);
    }

    // Do not match
    return memo[m][n] = max(lcsRec(s1, s2, m, n - 1, memo), lcsRec(s1, s2, m - 1, n, memo));
}

int lcs(char s1[],char s2[]){
      int m = strlen(s1);
    int n = strlen(s2);

    // Create memo table with fixed size
    int memo[MAX][MAX];
    for (int i = 0; i <= m; i++) {
        for (int j = 0; j <= n; j++) {
            // Initialize memo table with -1
            memo[i][j] = -1;
        }
    }

    return lcsRec(s1, s2, m, n, memo);
}

int main() {
    const char *s1 = "AGGTAB";
    const char *s2 = "GXTXAYB";

  
    printf("%d\n", lcs(s1, s2));

    return 0;
}
Java
import java.util.Arrays;

class GfG {
  
    // Returns length of LCS for s1[0..m-1], s2[0..n-1]
    static int lcsRec(String s1, String s2, int m, int n,
                   int[][] memo) {
        // Base Case
        if (m == 0 || n == 0)
            return 0;

        // Already exists in the memo table
        if (memo[m][n] != -1)
            return memo[m][n];

        // Match
        if (s1.charAt(m - 1) == s2.charAt(n - 1)) {
            return memo[m][n]
                = 1 + lcsRec(s1, s2, m - 1, n - 1, memo);
        }

        // Do not match
        return memo[m][n]
            = Math.max(lcsRec(s1, s2, m, n - 1, memo),
                       lcsRec(s1, s2, m - 1, n, memo));
    }
    static int lcs(String s1, String s2){
        int m = s1.length();
        int n = s2.length();
        int[][] memo = new int[m + 1][n + 1];

        // Initialize the memo table with -1
        for (int i = 0; i <= m; i++) {
            Arrays.fill(memo[i], -1);
        }

        return lcsRec(s1, s2, m, n, memo);
    } 
    public static void main(String[] args) {
        String s1 = "AGGTAB";
        String s2 = "GXTXAYB";

        System.out.println(lcs(s1, s2));
    }
}
Python
def lcsRec(s1, s2, m, n, memo):
    # Base Case
    if m == 0 or n == 0:
        return 0

    # Already exists in the memo table
    if memo[m][n] != -1:
        return memo[m][n]

    # Match
    if s1[m - 1] == s2[n - 1]:
        memo[m][n] = 1 + lcsRec(s1, s2, m - 1, n - 1, memo)
        return memo[m][n]

    # Do not match
    memo[m][n] = max(lcsRec(s1, s2, m, n - 1, memo),
                     lcsRec(s1, s2, m - 1, n, memo))
    return memo[m][n]


def lcs(s1, s2):
    m = len(s1)
    n = len(s2)
    memo = [[-1 for _ in range(n + 1)] for _ in range(m + 1)]
    return lcsRec(s1,s2,m,n,memo)
    
if __name__ == "__main__":
    s1 = "AGGTAB"
    s2 = "GXTXAYB"
    print(lcs(s1, s2))
C#
using System;
class GfG {

    // Returns length of LCS for s1[0..m-1], s2[0..n-1]
    static int lcsRec(string s1, string s2, int m,
                          int n, int[, ] memo) {
        // Base Case
        if (m == 0 || n == 0)
            return 0;

        // Already exists in the memo table
        if (memo[m, n] != -1)
            return memo[m, n];

        // Match
        if (s1[m - 1] == s2[n - 1]) {
            return memo[m, n]
                = 1 + lcsRec(s1, s2, m - 1, n - 1, memo);
        }

        // Do not match
        return memo[m, n]
            = Math.Max(lcsRec(s1, s2, m, n - 1, memo),
                       lcsRec(s1, s2, m - 1, n, memo));
    }
    
    static int lcs(string s1,string s2){
        int m = s1.Length;
        int n = s2.Length;
        
        int[, ] memo = new int[m + 1, n + 1];

        // Initialize memo array with -1
        for (int i = 0; i <= m; i++) {
            for (int j = 0; j <= n; j++) {
                memo[i, j] = -1;
            }
        }
        
        return lcsRec(s1,s2,m,n,memo);
    }

    public static void Main() {
        string s1 = "AGGTAB";
        string s2 = "GXTXAYB";
        
        Console.WriteLine(lcs(s1, s2));
    }
}
JavaScript
function lcsRec(s1, s2, m, n, memo)
{
    // Base Case
    if (m === 0 || n === 0)
        return 0;

    // Already exists in the memo table
    if (memo[m][n] !== -1)
        return memo[m][n];

    // Match
    if (s1[m - 1] === s2[n - 1]) {
        memo[m][n] = 1 + lcsRec(s1, s2, m - 1, n - 1, memo);
        return memo[m][n];
    }

    // Do not match
    memo[m][n] = Math.max(lcsRec(s1, s2, m, n - 1, memo),
                          lcsRec(s1, s2, m - 1, n, memo));
    return memo[m][n];
}

function lcs(s1, s2)
{

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

    return lcsRec(s1, s2, m, n, memo);
}
// driver code
const s1 = "AGGTAB";
const s2 = "GS1TS1AS2B";

console.log(lcs(s1, s2));

Output
4

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

There are two parameters that change in the recursive solution and these parameters go from 0 to m and 0 to n. So we create a 2D dp array of size (m+1) x (n+1).

  • We first fill the known entries when m is 0 or n is 0.
  • Then we fill the remaining entries using the recursive formula.

Say the strings are S1 = "AXTY" and S2 = "AYZX", Follow below :

C++
#include <iostream>
#include <vector>
using namespace std;

// Returns length of LCS for s1[0..m-1], s2[0..n-1]
int lcs(string &s1, string &s2) {
    int m = s1.size();
    int n = s2.size();

    // Initializing a matrix of size (m+1)*(n+1)
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));

    // Building dp[m+1][n+1] in bottom-up fashion
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (s1[i - 1] == s2[j - 1])
                dp[i][j] = dp[i - 1][j - 1] + 1;
            else
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
        }
    }

    // dp[m][n] contains length of LCS for s1[0..m-1]
    // and s2[0..n-1]
    return dp[m][n];
}

int main() {
    string s1 = "AGGTAB";
    string s2 = "GXTXAYB";
    cout << lcs(s1, s2) << endl;

    return 0;
}
C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int max(int x, int y);

// Function to find length of LCS for s1[0..m-1], s2[0..n-1]
int lcs(const char *S1, const char *S2) {
    int m = strlen(S1);
    int n = strlen(S2);

    // Initializing a matrix of size (m+1)*(n+1)
    int dp[m + 1][n + 1];

    // Building dp[m+1][n+1] in bottom-up fashion
    for (int i = 0; i <= m; i++) {
        for (int j = 0; j <= n; j++) {
          
            if (i == 0 || j == 0)
                dp[i][j] = 0;
            
            else if (S1[i - 1] == S2[j - 1])
                dp[i][j] = dp[i - 1][j - 1] + 1;

            else
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
        }
    }
   
    return dp[m][n];
}

int max(int x, int y) {
    return (x > y) ? x : y;
}

int main() {
    const char *S1 = "AGGTAB";
    const char *S2 = "GXTXAYB";
    printf("%d\n", lcs(S1, S2));

    return 0;
}
Java
import java.util.Arrays;

class GfG {
  
    // Returns length of LCS for s1[0..m-1], s2[0..n-1]
    static int lcs(String S1, String S2) {
        int m = S1.length();
        int n = S2.length();

        // Initializing a matrix of size (m+1)*(n+1)
        int[][] dp = new int[m + 1][n + 1];

        // Building dp[m+1][n+1] in bottom-up fashion
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (S1.charAt(i - 1) == S2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
                else {
                    dp[i][j] = Math.max(dp[i - 1][j],
                                        dp[i][j - 1]);
                }
            }
        }

        // dp[m][n] contains length of LCS for S1[0..m-1]
        // and S2[0..n-1]
        return dp[m][n];
    }

  
    public static void main(String[] args)
    {
        String S1 = "AGGTAB";
        String S2 = "GXTXAYB";
        System.out.println( lcs(S1, S2));
    }
}
Python
def lcs(S1, S2):
    m = len(S1)
    n = len(S2)

    # Initializing a matrix of size (m+1)*(n+1)
    dp = [[0] * (n + 1) for x in range(m + 1)]

    # Building dp[m+1][n+1] in bottom-up fashion
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if S1[i - 1] == S2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
            else:
                dp[i][j] = max(dp[i - 1][j],
                               dp[i][j - 1])

    # dp[m][n] contains length of LCS for S1[0..m-1]
    # and S2[0..n-1]
    return dp[m][n]


if __name__ == "__main__":
    S1 = "AGGTAB"
    S2 = "GXTXAYB"
    print(lcs(S1, S2))
C#
using System;

class GfG {
    // Returns length of LCS for S1[0..m-1], S2[0..n-1]
    static int lcs(string S1, string S2) {
        int m = S1.Length;
        int n = S2.Length;

        // Initializing a matrix of size (m+1)*(n+1)
        int[, ] dp = new int[m + 1, n + 1];

        // Building dp[m+1][n+1] in bottom-up fashion
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (S1[i - 1] == S2[j - 1]) {
                    dp[i, j] = dp[i - 1, j - 1] + 1;
                }
                else {
                    dp[i, j] = Math.Max(dp[i - 1, j],
                                        dp[i, j - 1]);
                }
            }
        }

        // dp[m, n] contains length of LCS for S1[0..m-1]
        // and S2[0..n-1]
        return dp[m, n];
    }

    static void Main() {
        string S1 = "AGGTAB";
        string S2 = "GXTXAYB";
        Console.WriteLine(lcs(S1, S2));
    }
}
JavaScript
function lcs(S1, S2) {
    const m = S1.length;
    const n = S2.length;

    // Initializing a matrix of size (m+1)*(n+1)
    const dp = Array.from({length : m + 1},
                          () => Array(n + 1).fill(0));

    // Building dp[m+1][n+1] in bottom-up fashion
    for (let i = 1; i <= m; i++) {
        for (let j = 1; j <= n; j++) {
            if (S1[i - 1] === S2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            }
            else {
                dp[i][j]
                    = Math.max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }

    // dp[m][n] contains length of LCS for
    // S1[0..m-1] and S2[0..n-1]
    return dp[m][n];
}

const S1 = "AGGTAB";
const S2 = "GXTXAYB";
console.log(lcs(S1, S2));

Output
4

[Expected Approach 2] Space Optimized - Two 1D Arrays - O(n * m) Time O(m) Space

One important observation in the above simple implementation is, in each iteration of the outer loop we only need values from all columns of the previous row. So there is no need to store all rows in our dp matrix, we can just store two rows at a time and use them. In that way, used space will be reduced from dp[m+1][n+1] to dp[2][n+1].

The recurrence relation for the Longest Common Subsequence (LCS) problem is:

If the last character of s1 and s2 match:

  • dp[i][j] = 1 + dp[i-1][j-1]

if the last characters of s1 and s2 do not match, we take the maximum of two cases:
1. exclude the last character of s1
2. exclude the last char of s2

  • dp[i][j] = max(dp[i-1][j],dp[i][j-1])

Base Case: when the length of either s1 or s2 is 0, LCS is 0.

  • for i = 0 or j = 0 dp[i][j] = 0

In the recurrance relation one things that we can observe is for finding the current state dp[i][j] we don't need to store the entire table, we only need to store the current row and the previous row because each value at position (i, j) in the table only depends on:

  • The value directly above it (dp[i-1][j]),
  • The value directly to the left (dp[i][j-1]),
  • The value diagonally left above it (dp[i-1][j-1]).

Since only the previous row and the current row are required to compute the LCS, we can reduce the space by using just two rows instead of the entire table. We use a 2D array of size 2 x (n+1) to store only two rows at a time.
We have used two array to store the previous and current row, prev for previous row and curr for current row, once the iteration for current row is done, we will set prev = curr, so that curr row can serve as prev for next index.

C++
#include <iostream>   
#include <string>    
#include <algorithm> 
using namespace std;

int lcs(string& s1, string& s2) {
   
    int n = s1.size();
    int m = s2.size();

    // Initialize two vectors to store the current 
  	// and previous rows of the DP table
    vector<int> prev(m + 1, 0), cur(m + 1, 0);

    // Base case is covered as we have initialized 
  	// the prev and cur vectors to 0.

    for (int ind1 = 1; ind1 <= n; ind1++) {
        for (int ind2 = 1; ind2 <= m; ind2++) {
            if (s1[ind1 - 1] == s2[ind2 - 1]) {
              
                // Characters match, increment LCS length
                cur[ind2] = 1 + prev[ind2 - 1];
            }
            else
                // Characters don't match, consider the
              	// maximum from above or left
                cur[ind2] = max(prev[ind2], cur[ind2 - 1]);
        }
      
        // Update the previous row with the current row
        prev = cur;
    }
  
    // Return the length of the Longest Common Subsequence
    return prev[m];
}
int main() {

    string s1 = "AGGTAB";
    string s2 = "GXTXAYB";
    int res = lcs(s1, s2);
    cout << res;
    return 0;
}
Java
class GfG {

    static int lcs(String s1, String s2) {
      
        int n = s1.length();
        int m = s2.length();

        // Create arrays to store the LCS lengths
        int prev[] = new int[m + 1];
        int cur[] = new int[m + 1];

        // Iterate through the strings and calculate LCS
        // lengths
        for (int ind1 = 1; ind1 <= n; ind1++) {
            for (int ind2 = 1; ind2 <= m; ind2++) {

                // If the characters at the current indices
                // are the same, increment the LCS length
                if (s1.charAt(ind1 - 1)
                    == s2.charAt(ind2 - 1))
                    cur[ind2] = 1 + prev[ind2 - 1];
              
                // If the characters are different, choose
                // the maximum LCS length by either
                // excluding a character in s1 or excluding
                // a character in s2
                else
                    cur[ind2] = Math.max(prev[ind2],
                                         cur[ind2 - 1]);
            }
          
            // Update the 'prev' array to the values of
            // 'cur' for the next iteration
            prev = (int[])(cur.clone());
        }

        // Return the length of the Longest Common
        // Subsequence (LCS)
        return prev[m];
    }

    public static void main(String[] args) {

        String s1 = "AGGTAB";
        String s2 = "GXTXAYB";
        int res = lcs(s1, s2);
        System.out.println(res);
    }
}
Python
def lcs(s1, s2):
    n = len(s1)
    m = len(s2)

    # Initialize two arrays, 'prev' and 'cur',
    # to store the DP values
    prev = [0] * (m + 1)
    cur = [0] * (m + 1)

    # Loop through the characters of both strings
    # to compute LCS
    for ind1 in range(1, n + 1):
        for ind2 in range(1, m + 1):
            if s1[ind1 - 1] == s2[ind2 - 1]:
              
                # If the characters match, increment
                # LCS length by 1
                cur[ind2] = 1 + prev[ind2 - 1]
            else:
              
                # If the characters do not match, take 
                # the maximum of LCS
                # by excluding one character from s1 or s2
                cur[ind2] = max(prev[ind2], cur[ind2 - 1])

        # Update 'prev' to be the same as 'cur' for the 
        # next iteration
        prev = cur[:]

    # The value in 'prev[m]' represents the length of the 
    # Longest Common Subsequence
    return prev[m]


if __name__ == "__main__":
    s1 = "AGGTAB"
    s2 = "GXTXAYB"
    print(lcs(s1, s2))
C#
using System;

class GfG {

    static int lcs(string s1, string s2) {
        int n = s1.Length;
        int m = s2.Length;

        // Initialize two arrays to store the current
        // and previous rows of the DP table
        int[] prev = new int[m + 1];
        int[] cur = new int[m + 1];

        // Base case is implicitly handled as the arrays are
        // initialized to 0

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (s1[i - 1] == s2[j - 1]) {
                  
                    // Characters match, increment LCS
                    // length
                    cur[j] = 1 + prev[j - 1];
                }
                else {
                  
                    // Characters don't match, consider the
                    // maximum from above or left
                    cur[j] = Math.Max(prev[j], cur[j - 1]);
                }
            }

            // Update the previous row with
          	// the current row
            Array.Copy(cur, prev, m + 1);
        }

        // Return the length of the Longest Common
        // Subsequence
        return prev[m];
    }

    static void Main() {

        string s1 = "AGGTAB";
        string s2 = "GXTXAYB";
        int res = lcs(s1, s2);
        Console.WriteLine(res);
    }
}
JavaScript
function lcs(s1, s2) {
    const n = s1.length;
    const m = s2.length;

    // Initialize arrays 'prev' and 'cur' to store dynamic
    // programming results, both initialized with 0
    const prev = new Array(m + 1).fill(0);
    const cur = new Array(m + 1).fill(0);

    // Base case is already covered as 'prev' and 'cur' are
    // initialized to 0.

    // Populating the 'cur' array using nested loops
    for (let ind1 = 1; ind1 <= n; ind1++) {
        for (let ind2 = 1; ind2 <= m; ind2++) {
            if (s1[ind1 - 1] === s2[ind2 - 1]) {
                cur[ind2] = 1 + prev[ind2 - 1];
            }
            else {
                cur[ind2]
                    = Math.max(prev[ind2], cur[ind2 - 1]);
            }
        }
        
        // Update 'prev' with the values of 'cur' for the
        // next iteration
        prev.splice(0, m + 1, ...cur);
    }

    // The result is stored in the last element of the
    // 'prev' array
    return prev[m];
}

const s1 = "AGGTAB";
const s2 = "GXTXAYB";
const res = lcs(s1, s2);
console.log(res);

Output
4

Time Complexity : O(n * m), where m is the length of string s1 and n is the length of string s2.
Auxiliary Space: O(m), Only two 1D arrays are used, each of size m+1.

[Expected Approach 3] Further Space Optimized - Single Array - O(m*n) Time and O(n) Space

In this approach, the auxiliary space is further optimized by using a single DP array, where:
dp[j] represents the value of dp[i-1][j] (previous row's value) before updating. During the computation, dp[j] is updated to represent the current row value dp[i][j]
Now the recurrance relations become:

  • if the characters s1[i-1] and s2[j-1] match, dp[j] = 1+ prev. Here, prev is a temporary variable storing the diagonal value (dp[i-1][j-1]).
  • If the characters don't match, dp[j] = max(dp[j-1], dp[j]). Here dp[j] represents the value of dp[i-1][j] before updating and dp[j-1] represents the value of dp[i-1][j].
C++
#include <iostream>
#include <vector>
using namespace std;

int lcs(string &s1, string &s2) {
  
    int m = s1.length(), n = s2.length();

    // dp vector is initialized to all zeros
    // This vector stores the LCS values for the current row.
    // dp[j] represents LCS of s1[0..i] and s2[0..j]
    vector<int> dp(n + 1, 0);

    // i and j represent the lengths of s1 and s2 respectively
    for (int i = 1; i <= m; ++i) {

        // prev stores the value from the previous
        // row and previous column (i-1), (j -1)
        // Used to keep track of LCS[i-1][j-1] while updating dp[j]
        int prev = dp[0];

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

            // temp temporarily stores the current
            // dp[j] before it gets updated
            int temp = dp[j];

            // If characters match, add 1 to the value
            // from the previous row and previous column
            // dp[j] = 1 + LCS[i-1][j-1]
            if (s1[i - 1] == s2[j - 1])
                dp[j] = 1 + prev;
            else
                // Otherwise, take the maximum of the
                // left (dp[j-1]) and top (dp[j]) values
                dp[j] = max(dp[j - 1], dp[j]);

            // Update prev for the next iteration
            // This keeps the value of the previous
          // row (i-1) for future comparisons
            prev = temp;
        }
    }

    // The last element of the vector contains the length of the LCS
    // dp[n] stores the length of LCS of s1[0..m] and s2[0..n]
    return dp[n];
}

int main() {
    string s1 = "AGGTAB", s2 = "GXTXAYB";
    cout << lcs(s1, s2);
    return 0;
}
Java
class GfG {
   
    static int lcs(String s1, String s2) {
        int m = s1.length();
        int n = s2.length();
        
        // dp array is initialized to all zeros
        int[] dp = new int[n + 1];

        // i and j represent the lengths of s1 and s2 respectively
        for (int i = 1; i <= m; ++i) {
          
            // prev stores the value from the previous 
            // row and previous column (i-1), (j -1)
            int prev = dp[0];  
      
            for (int j = 1; j <= n; ++j) {
              
                // temp temporarily stores the current 
                // dp[j] before it gets updated
                int temp = dp[j];  
                if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                  
                    // If characters match, add 1 to the value 
                    // from the previous row and previous column
                    dp[j] = 1 + prev;  
                } else {
                  
                    // Otherwise, take the maximum of the 
                    // left and top values
                    dp[j] = Math.max(dp[j - 1], dp[j]);  
                }
              
                // Update prev for the next iteration
                prev = temp;  
            }
        }

        // The last element of the array contains 
      	// the length of the LCS
        return dp[n];
    }

    public static void main(String[] args) {
        String s1 = "AGGTAB";
        String s2 = "GXTXAYB";
        int res = lcs(s1, s2);
        System.out.println(res);
    }
}
Python
def lcs(s1, s2):
    m = len(s1)
    n = len(s2)
    
    # dp array is initialized to all zeros
    dp = [0] * (n + 1)

    # i and j represent the lengths of s1 
    # and s2 respectively
    for i in range(1, m + 1):
      
        # prev stores the value from the previous 
        # row and previous column (i-1), (j -1)
        prev = dp[0]
      
        for j in range(1, n + 1):
          
            # temp temporarily stores the current 
            # dp[j] before it gets updated
            temp = dp[j]
            if s1[i - 1] == s2[j - 1]:
              
                # If characters match, add 1 to the value 
                # from the previous row and previous column
                dp[j] = 1 + prev
            else:
              
                # Otherwise, take the maximum of the 
                # left and top values
                dp[j] = max(dp[j - 1], dp[j])
                
            # Update prev for the next iteration
            prev = temp
      
    # The last element of the list contains
    # the length of the LCS
    return dp[n]
 
if __name__ == "__main__":
    s1 = "AGGTAB"
    s2 = "GXTXAYB"
    res = lcs(s1, s2)
    print(res)
C#
using System;

class GfG {
   
    static int lcs(string s1, string s2) {
        int m = s1.Length;
        int n = s2.Length;
        
        // dp array is initialized to all zeros
        int[] dp = new int[n + 1];

        // i and j represent the lengths of 
       // s1 and s2 respectively
        for (int i = 1; i <= m; ++i) {
          
            // prev stores the value from the previous 
            // row and previous column (i-1), (j -1)
            int prev = dp[0];
      
            for (int j = 1; j <= n; ++j) {
              
                // temp temporarily stores the current 
                // dp[j] before it gets updated
                int temp = dp[j];
                if (s1[i - 1] == s2[j - 1]) {
                  
                    // If characters match, add 1 to the value 
                    // from the previous row and previous column
                    dp[j] = 1 + prev;
                } else {
                  
                    // Otherwise, take the maximum of the 
                    // left and top values
                    dp[j] = Math.Max(dp[j - 1], dp[j]);
                }
              
                // Update prev for the next iteration
                prev = temp;
            }
        }

        // The last element of the array 
      	// contains the length of the LCS
        return dp[n];
    }
 
    static void Main() {
        string s1 = "AGGTAB";
        string s2 = "GXTXAYB";
        int res = lcs(s1, s2);
        Console.WriteLine(res);
    }
}
JavaScript
function lcs(s1, s2) {
    const m = s1.length;
    const n = s2.length;

    // dp array is initialized to all zeros
    const dp = Array(n + 1).fill(0);

    // i and j represent the lengths of s1 and s2
    // respectively
    for (let i = 1; i <= m; ++i) {

        // prev stores the value from the previous
        // row and previous column (i-1), (j -1)
        let prev = dp[0];

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

            // temp temporarily stores the current
            // dp[j] before it gets updated
            const temp = dp[j];
            if (s1[i - 1] === s2[j - 1]) {

                // If characters match, add 1 to the value
                // from the previous row and previous column
                dp[j] = 1 + prev;
            }
            else {

                // Otherwise, take the maximum of the
                // left and top values
                dp[j] = Math.max(dp[j - 1], dp[j]);
            }

            // Update prev for the next iteration
            prev = temp;
        }
    }

    // The last element of the array 
    // contains the length of the LCS
    return dp[n];
}

const s1 = "AGGTAB";
const s2 = "GXTXAYB";
const res = lcs(s1, s2);
console.log(res);

Output
4

Applications of LCS

  • Used in diff utility to find differences between two data sources.
  • Helps identify common parts and highlight changes between files.
  • Widely used in version control systems (like Git) to track file changes.
  • Detects additions, deletions, and modifications between different versions of files.

Problems based on LCS

Comment