Open In App

LCS (Longest Common Subsequence) of three strings

Last Updated : 03 Jun, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given three strings s1, s2 and s3. Your task is to find the longest common sub-sequence in all three given sequences.

Note: This problem is simply an extension of LCS.

Examples: 

Input: s1 = "geeks" , s2 = "geeksfor", s3 = "geeksforgeeks"
Output : 5
Explanation: Longest common subsequence is "geeks" i.e., length = 5

Input: s1= "abcd1e2" , s2= "bc12ea" , s3= "bd1ea"
Output: 3
Explanation: Longest common subsequence is "b1e" i.e. length = 3.

[Naive Approach] Using Recursion – O(3^(n1+n2+n3)) Time and O(min(n1, n2, n3)) Space

The idea is to break the problem into smaller subproblems and then combine the solutions to solve the original problem using recursion. We compare the last characters of the three strings, and there are two cases to consider:

  • When the last characters match: In this case, we reduce the problem by recursively calling the function for smaller substrings, removing the last character from each string.
  • When the last characters do not match: Here, we need to consider the maximum result from three different cases, each time excluding one character from one of the strings.

Base Cases: If any of the strings s1, s2, or s3 has a length of 0, the Longest Common Subsequence (LCS) is 0.


Recurrence Relation:
If the last characters of s1s2, and s3 are the same: These characters contribute to the LCS. Therefore, we add 1 to the LCS and call the recursive function with the previous characters of all three strings:

  • LCSof3(n1, n2, n3) = 1 + LCSof3(n1-1, n2-1, n3-1)

If the last characters do not match, we consider three possibilities:

  • Exclude the last character of s1 and compute the LCS for s1[0..n1-2], s2, and s3
    LCSof3(n1, n2, n3) = LCSof3(n1-1, n2, n3)
  • Exclude the last character of s2 and compute the LCS for s1, s2[0..n2-2], and s3
    LCSof3(n1, n2, n3) = LCSof3(n1, n2-1, n3)
  • Exclude the last character of s3 and compute the LCS for s1, s2, and s3[0..n3-2]
    LCSof3(n1, n2, n3) = LCSof3(n1, n2, n3-1)

Thus, the final LCS is the maximum result obtained from these three cases:

  • LCSof3(n1, n2, n3) = max(LCSof3(n1-1, n2 , n3), LCSof3(n1, n2-1, n3), LCSof3(n1, n2, n3-1))
C++
// C++ program to find the Longest Common Subsequence of
// three string using recursion

#include <bits/stdc++.h>
using namespace std;
int findLCSOf3(string& s1, string& s2, string& s3, int n1, int n2, int n3) {
  
    // Base case: If any of the strings is empty
    if (n1 == 0 || n2 == 0 || n3 == 0)
        return 0;

    // If last characters of s1, s2, and s3 are the same
    if (s1[n1 - 1] == s2[n2 - 1] && s2[n2 - 1] == s3[n3 - 1])
        return 1 + findLCSOf3(s1, s2, s3, n1 - 1, n2 - 1, n3 - 1);

    // If last characters are not the same, calculate
    // LCS by excluding one string at a time
    return max({ 
                findLCSOf3(s1, s2, s3, n1 - 1, n2, n3),
                findLCSOf3(s1, s2, s3, n1, n2 - 1, n3),
                findLCSOf3(s1, s2, s3, n1, n2, n3 - 1)});
}

int lcsOf3(string& s1, string& s2, string& s3) {
    int n1 = s1.size();
    int n2 = s2.size();
    int n3 = s3.size();
    int res = findLCSOf3(s1, s2, s3, n1, n2, n3);
    return res;
}

int main() {
    string s1 = "AGGT12";
    string s2 = "12TXAYB";
    string s3 = "12XBA";
    int res = lcsOf3(s1, s2, s3);
    cout << res ;
    return 0;
}
Java
// Java program to find the Longest Common Subsequence of
// three string using recursion

class GfG {
    static int findLCSOf3(String s1, String s2, String s3,
                          int n1, int n2, int n3) {
      
        // Base case: If any of the strings is empty
        if (n1 == 0 || n2 == 0 || n3 == 0)  
            return 0;
        
        // If last characters of s1, s2, and s3 are the same
        if (s1.charAt(n1 - 1) == s2.charAt(n2 - 1)
            && s2.charAt(n2 - 1) == s3.charAt(n3 - 1)) {
            return 1
                + findLCSOf3(s1, s2, s3, n1 - 1, n2 - 1,
                             n3 - 1);
        }

        // If last characters are not the same, calculate
        // LCS by excluding one string at a time
        return Math.max(
            Math.max(
                findLCSOf3(s1, s2, s3, n1 - 1, n2, n3),
                findLCSOf3(s1, s2, s3, n1, n2 - 1, n3)),
            findLCSOf3(s1, s2, s3, n1, n2, n3 - 1));
    }

    static int lcsOf3(String s1, String s2, String s3) {
        int n1 = s1.length();
        int n2 = s2.length();
        int n3 = s3.length();
        return findLCSOf3(s1, s2, s3, n1, n2, n3);
    }

    public static void main(String[] args) {
        String s1 = "AGGT12";
        String s2 = "12TXAYB";
        String s3 = "12XBA";
        int res = lcsOf3(s1, s2, s3);
        System.out.print(res);
    }
}
Python
# Python program to find the Longest Common Subsequence of
# three string using recursion


def findLCSOf3(s1, s2, s3, n1, n2, n3):

    # Base case: If any of the strings is empty
    if n1 == 0 or n2 == 0 or n3 == 0:
        return 0

    # If last characters of s1, s2, and s3 are the same
    if s1[n1 - 1] == s2[n2 - 1] == s3[n3 - 1]:
        return 1 + findLCSOf3(s1, s2, s3, n1 - 1, n2 - 1, n3 - 1)

    # If last characters are not the same, calculate
    # LCS by excluding one string at a time
    return max(
        findLCSOf3(s1, s2, s3, n1 - 1, n2, n3),
        findLCSOf3(s1, s2, s3, n1, n2 - 1, n3),
        findLCSOf3(s1, s2, s3, n1, n2, n3 - 1)
    )


def lcsOf3(s1, s2, s3):
    n1 = len(s1)
    n2 = len(s2)
    n3 = len(s3)
    return findLCSOf3(s1, s2, s3, n1, n2, n3)


if __name__ == "__main__":
    s1 = "AGGT12"
    s2 = "12TXAYB"
    s3 = "12XBA"
    res = lcsOf3(s1, s2, s3)
    print(res)
C#
// C# program to find the Longest Common Subsequence of
// three string

using System;

class GfG {
    static int findLCSOf3(string s1, string s2, string s3,
                          int n1, int n2, int n3) {
      
        // Base case: If any of the strings is empty
        if (n1 == 0 || n2 == 0 || n3 == 0)
            return 0;

        // If last characters of s1, s2, and s3 are the same
        if (s1[n1 - 1] == s2[n2 - 1]
            && s2[n2 - 1] == s3[n3 - 1])
            return 1
                + findLCSOf3(s1, s2, s3, n1 - 1, n2 - 1,
                             n3 - 1);

        // If last characters are not the same, calculate
        // LCS by excluding one string at a time
        return Math.Max(Math.Max(findLCSOf3(s1, s2, s3, n1 - 1, n2, n3),
                                findLCSOf3(s1, s2, s3, n1, n2 - 1, n3)),
                                findLCSOf3(s1, s2, s3, n1, n2, n3 - 1));
    }

    static int lcsOf3(string s1, string s2, string s3) {
        int n1 = s1.Length;
        int n2 = s2.Length;
        int n3 = s3.Length;
        return findLCSOf3(s1, s2, s3, n1, n2, n3);
    }

    static void Main() {
        string s1 = "AGGT12";
        string s2 = "12TXAYB";
        string s3 = "12XBA";
        int res = lcsOf3(s1, s2, s3);
        Console.WriteLine(res);
    }
}
JavaScript
// JavaScript program to find the Longest Common Subsequence
// of three string

function findLCSOf3(s1, s2, s3, n1, n2, n3) {
   
    // Base case: If any of the strings is empty
    if (n1 === 0 || n2 === 0 || n3 === 0) {
        return 0;
    }

    // If last characters of s1, s2, and s3 are the same
    if (s1[n1 - 1] === s2[n2 - 1]
        && s2[n2 - 1] === s3[n3 - 1]) {
        return 1
               + findLCSOf3(s1, s2, s3, n1 - 1, n2 - 1,
                            n3 - 1);
    }

    // If last characters are not the same, calculate LCS by
    // excluding one string at a time
    return Math.max(
        findLCSOf3(s1, s2, s3, n1 - 1, n2, n3),
        Math.max(findLCSOf3(s1, s2, s3, n1, n2 - 1, n3),
                 findLCSOf3(s1, s2, s3, n1, n2, n3 - 1)));
}

function lcsOf3(s1, s2, s3) {
    let n1 = s1.length;
    let n2 = s2.length;
    let n3 = s3.length;
    return findLCSOf3(s1, s2, s3, n1, n2, n3);
}

// Driver Code
let s1 = "AGGT12";
let s2 = "12TXAYB";
let s3 = "12XBA";
let res = lcsOf3(s1, s2, s3);
console.log(res);

Output
2

[Better Approach 1] Using Top-Down DP (Memoization) – O(n1*n2*n3) Time and O(n1*n2*n3) 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 solution to the Longest Common Subsequence (LCS) of three strings can be derived from the optimal solutions of smaller subproblems. Specifically, for given strings s1, s2, and s3 with lengths n1, n2, and n3, we can express the recursive relation as follows:

  • If the last characters of s1, s2, and s3 are the same:
    LCSof3(n1, n2, n3) = 1+LCSof3(n1-1, n2-1, n3-1)
  • If the last characters do not match, we consider three possibilities. the final LCS is the maximum result obtained from these three cases:
    LCSof3(n1, n2, n3)=max(LCSof3(n1-1, n2, n3),LCSof3(n1, n2-1, n3), LCSof3(n1, n2, n3-1))

2. Overlapping Subproblems:

  • When using a recursive approach to solve the Longest Common Subsequence (LCS) problem for three strings, we observe that many subproblems are computed multiple times. For example, when calculating LCSof3(s1, s2, s3) for strings s1, s2, and s3 with lengths n1, n2, and n3, we may end up recomputing the LCS for the same combinations of string prefixes multiple times.
  • The recursive(previous) solution involves changing three parameters: the current indices of the three strings (n1, n2, n3). We need to track these parameters, so we create a 3D array of size (n1+1) x (n2+1) x (n3+1), where n1, n2, and n3 represent the lengths of strings s1, s2, and s3. This array is used to store the results of subproblems for each combination of indices in the three strings.
  • We initialize the 3D array with -1 to indicate that no subproblems have been computed yet.
  • We check if the value at memo[n1][n2][n3] is -1. If it is, we proceed to compute the result. otherwise, we return the stored result.
C++
// C++ program to find the Longest Common Subsequence of
// three string using memoization

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

int findLCSOf3(string& s1, string& s2, string& s3, int n1, int n2, int n3,
               vector<vector<vector<int>>> &memo) {

    // Base case: If any of the strings is empty
    if (n1 == 0 || n2 == 0 || n3 == 0)
        return 0;

    if (memo[n1][n2][n3] != -1)
        return memo[n1][n2][n3];

    // If last characters of s1, s2, and s3 are the same
    if (s1[n1 - 1] == s2[n2 - 1] && s2[n2 - 1] == s3[n3 - 1])
        return memo[n1][n2][n3] = 1 + findLCSOf3(s1, s2,
								s3, n1 - 1, n2 - 1, n3 - 1, memo);

    // If last characters are not the same, calculate
    // LCS by excluding one string at a time
    return memo[n1][n2][n3] = max({findLCSOf3(s1, s2, s3, n1 - 1, n2, n3, memo),
                                  findLCSOf3(s1, s2, s3, n1, n2 - 1, n3, memo),
                                  findLCSOf3(s1, s2, s3, n1, n2, n3 - 1, memo)});
}

int lcsOf3(string& s1, string& s2, string& s3) {
    int n1 = s1.size();
    int n2 = s2.size();
    int n3 = s3.size();
    vector<vector<vector<int>>> memo = vector<vector<vector<int>>>(n1 + 1, 
		vector<vector<int>>(n2 + 1, vector<int>(n3 + 1, -1)));
    int res = findLCSOf3(s1, s2, s3, n1, n2, n3, memo);
    return res;
}

int main() {
    string s1 = "AGGT12";
    string s2 = "12TXAYB";
    string s3 = "12XBA";
    int res = lcsOf3(s1, s2, s3);
    cout << res ;

    return 0;
}
Java
// Java program to find the Longest Common Subsequence of
// three string using  memoization

import java.util.*;

class GfG {

    static int findLCSOf3(String s1, String s2, String s3, int n1, int n2, int n3,
                          int[][][] memo) {
      
        // Base case: If any of the strings is empty
        if (n1 == 0 || n2 == 0 || n3 == 0)
            return 0;

        // If the result is already computed, return it from
        // the memo table
        if (memo[n1][n2][n3] != -1)
            return memo[n1][n2][n3];

        // If the last characters of s1, s2, and s3 are the
        // same
        if (s1.charAt(n1 - 1) == s2.charAt(n2 - 1)
            && s2.charAt(n2 - 1) == s3.charAt(n3 - 1))
            return memo[n1][n2][n3]
                = 1 + findLCSOf3(s1, s2, s3, n1 - 1, n2 - 1, n3 - 1, memo);

        // If last characters do not match, calculate LCS by
        // excluding one string at a time
        return memo[n1][n2][n3] = Math.max(
                   Math.max(findLCSOf3(s1, s2, s3, n1 - 1, n2, n3, memo),
                            findLCSOf3(s1, s2, s3, n1, n2 - 1, n3, memo)),
                            findLCSOf3(s1, s2, s3, n1, n2, n3 - 1, memo));
    }

    static int lcsOf3(String s1, String s2, String s3) {
        int n1 = s1.length();
        int n2 = s2.length();
        int n3 = s3.length();

        // Initialize the memo table with -1
        int[][][] memo = new int[n1 + 1][n2 + 1][n3 + 1];
        for (int i = 0; i <= n1; i++) {
            for (int j = 0; j <= n2; j++) {
                for (int k = 0; k <= n3; k++) {
                    memo[i][j][k] = -1;
                }
            }
        }
        return findLCSOf3(s1, s2, s3, n1, n2, n3, memo);
    }

    public static void main(String[] args) {
        String s1 = "AGGT12";
        String s2 = "12TXAYB";
        String s3 = "12XBA";
        int res = lcsOf3(s1, s2, s3);
       System.out.print(res);
    }
}
Python
 # Python program to find the Longest Common Subsequence of
# three string using memoization

def findLCSOf3(s1, s2, s3, n1, n2, n3, memo):
  
    # Base case: If any of the strings is empty
    if n1 == 0 or n2 == 0 or n3 == 0:
        return 0

    # If the result is already computed, 
    # return it from the memo table
    if memo[n1][n2][n3] != -1:
        return memo[n1][n2][n3]

    # If the last characters of s1, s2, and s3 are the same
    if s1[n1 - 1] == s2[n2 - 1] and s2[n2 - 1] == s3[n3 - 1]:
        memo[n1][n2][n3] = 1 + \
            findLCSOf3(s1, s2, s3, n1 - 1, n2 - 1, n3 - 1, memo)
        return memo[n1][n2][n3]

    # If last characters do not match, 
    # calculate LCS by excluding one string at a time
    memo[n1][n2][n3] = max(
        findLCSOf3(s1, s2, s3, n1 - 1, n2, n3, memo),
        findLCSOf3(s1, s2, s3, n1, n2 - 1, n3, memo),
        findLCSOf3(s1, s2, s3, n1, n2, n3 - 1, memo)
    )
    return memo[n1][n2][n3]


def lcsOf3(s1, s2, s3):
    n1, n2, n3 = len(s1), len(s2), len(s3)

    # Initialize the memoization table with -1
    memo = [[[-1 for _ in range(n3 + 1)]
             for _ in range(n2 + 1)] for _ in range(n1 + 1)]

    # Call the recursive function
    return findLCSOf3(s1, s2, s3, n1, n2, n3, memo)


 
s1 = "AGGT12"
s2 = "12TXAYB"
s3 = "12XBA"
res = lcsOf3(s1, s2, s3);
print(res)
C#
// C# program to find the Longest Common Subsequence of
// three string using memoization

using System;

class GfG {
   
    static int findLCSOf3(string s1, string s2, string s3, int n1, int n2, int n3,
                          int[, , ] memo) {
      
        // Base case: If any of the strings is empty
        if (n1 == 0 || n2 == 0 || n3 == 0)
            return 0;

        // If the result is already computed, return it from
        // the memo table
        if (memo[n1, n2, n3] != -1)
            return memo[n1, n2, n3];

        // If the last characters of s1, s2, and s3 are the
        // same
        if (s1[n1 - 1] == s2[n2 - 1]
            && s2[n2 - 1] == s3[n3 - 1]) {
            memo[n1, n2, n3]
                = 1
                  + findLCSOf3(s1, s2, s3, n1 - 1, n2 - 1,
                               n3 - 1, memo);
            return memo[n1, n2, n3];
        }

        // If last characters do not match, calculate LCS by
        // excluding one string at a time
        memo[n1, n2, n3] = Math.Max(
            Math.Max(findLCSOf3(s1, s2, s3, n1 - 1, n2, n3,memo),
                     findLCSOf3(s1, s2, s3, n1, n2 - 1, n3, memo)),
                     findLCSOf3(s1, s2, s3, n1, n2, n3 - 1, memo));

        return memo[n1, n2, n3];
    }

    
    static int lcsOf3(string s1, string s2, string s3) {
        int n1 = s1.Length;
        int n2 = s2.Length;
        int n3 = s3.Length;

        // Initialize the memoization table with -1
        int[, , ] memo = new int[n1 + 1, n2 + 1, n3 + 1];
        for (int i = 0; i <= n1; i++) {
            for (int j = 0; j <= n2; j++) {
                for (int k = 0; k <= n3; k++) {
                    memo[i, j, k]
                        = -1;  
                }
            }
        }
        return findLCSOf3(s1, s2, s3, n1, n2, n3, memo);
    }

    static void Main() {
        string s1 = "AGGT12";
        string s2 = "12TXAYB";
        string s3 = "12XBA";
       int res = lcsOf3(s1, s2, s3);
        Console.WriteLine(res);
    }
}
JavaScript
// JavaScript program to find the Longest Common Subsequence of
// three string using memoization

function findLCSOf3(s1, s2, s3, n1, n2, n3, memo) {

    // Base case: If any of the strings is empty
    if (n1 === 0 || n2 === 0 || n3 === 0) {
        return 0;
    }

    // If the result is already computed, return it from the
    // memo table
    if (memo[n1][n2][n3] !== -1) {
        return memo[n1][n2][n3];
    }

    // If the last characters of s1, s2, and s3 are the same
    if (s1[n1 - 1] === s2[n2 - 1] && s2[n2 - 1] === s3[n3 - 1]) {
        memo[n1][n2][n3]
            = 1+ findLCSOf3(s1, s2, s3, n1 - 1, n2 - 1, n3 - 1, memo);
        return memo[n1][n2][n3];
    }

    // If last characters do not match, calculate LCS by
    // excluding one string at a time
    memo[n1][n2][n3] = Math.max(
        Math.max(
            findLCSOf3(s1, s2, s3, n1 - 1, n2, n3, memo),
            findLCSOf3(s1, s2, s3, n1, n2 - 1, n3, memo)),
        findLCSOf3(s1, s2, s3, n1, n2, n3 - 1, memo));

    return memo[n1][n2][n3];
}

function lcsOf3(s1, s2, s3) {
    const n1 = s1.length;
    const n2 = s2.length;
    const n3 = s3.length;

    // Initialize the memoization table with -1
    const memo = Array.from(
        {length : n1 + 1},
        () => Array.from({length : n2 + 1},
                         () => Array(n3 + 1).fill(-1)));

    // Call the recursive function
    return findLCSOf3(s1, s2, s3, n1, n2, n3, memo);
}

const s1 = "AGGT12";
const s2 = "12TXAYB";
const s3 = "12XBA";
const res = lcsOf3(s1, s2, s3);
console.log(res);

Output
2

[Better Apporach 2] Using Bottom-Up DP – O(n1*n2*n3) Time and O(n1*n2*n3) 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.

We create a 3D DP array of size (n1 + 1) * (n2 + 1) * (n3 + 1) where each state dp[i][j][k] represents the length of the Longest Common Subsequence (LCS) of the first i characters of string s1, the first j characters of string s2, and the first k characters of string s3.

The dynamic programming relation for LCS of three strings is as follows:

Base case: If any of the strings is empty (i == 0, j == 0, or k == 0), the LCS is 0:
if i == 0 or j == 0 or k == 0 dp[i][j][k] = 0

Relation:
If the last characters of s1, s2, and s3 are the same, they contribute to the LCS. We add 1 to the result of the subproblem that excludes the last character from each string:
if s1[i-1] == s2[j-1] && s2[j-1] == s3[k-1] dp[i][j][k] = dp[i-1][j-1][k-1] + 1

If the last characters do not match, we need to check three cases:

  • Exclude the last character of s1: In this case, we compute the LCS by considering the first i-1 characters of s1, the first j characters of s2, and the first k characters of s3:
    dp[i][j][k] = dp[i-1][j][k]
  • Exclude the last character of s2: In this case, we compute the LCS by considering the first i characters of s1, the first j-1 characters of s2, and the first k characters of s3:
    dp[i][j][k] = dp[i][j-1][k]
  • Exclude the last character of s3: In this case, we compute the LCS by considering the first i characters of s1, the first j characters of s2, and the first k-1 characters of s3:
    dp[i][j][k] = dp[i][j][k-1]

The final result, dp[n1][n2][n3], gives the length of the LCS of the three strings.

C++
// C++ program to find the Longest Common Subsequence of
// three string using tabulation

#include <bits/stdc++.h>
using namespace std;
 
int lcsOf3(string& s1, string& s2, string& s3) {
    int n1 = s1.length();
    int n2 = s2.length();
    int n3 = s3.length();

   // Create a 3D array (dp) to store the 
   // LCS lengths for each combination of substrings
    int dp[n1 + 1][n2 + 1][n3 + 1];

    /* dp[i][j][k] contains length of LCS of
       s1[0..i-1], s2[0..j-1] and s3[0..k-1] */
    for (int i = 0; i <= n1; i++) {
        for (int j = 0; j <= n2; j++) {
            for (int k = 0; k <= n3; k++) {
                if (i == 0 || j == 0 || k == 0)
                    dp[i][j][k] = 0;  

                else if (s1[i - 1] == s2[j - 1] && s1[i - 1] == s3[k - 1])
                    dp[i][j][k] = dp[i - 1][j - 1][k - 1] + 1;  

                else
                    dp[i][j][k] = max(max(dp[i - 1][j][k], dp[i][j - 1][k]),
                                      dp[i][j][k - 1]);  
            }
        }
    }
    return dp[n1][n2][n3];
}

 
int main() {
    string s1 = "AGGT12";
    string s2 = "12TXAYB";
    string s3 = "12XBA";
    int res = lcsOf3(s1, s2, s3);
    cout << res << endl;

    return 0;
}
Java
// Java program to find the Longest Common Subsequence of
// three string using tabulation

class GfG {
  
      static int lcsOf3(String s1, String s2, String s3) {
        int n1 = s1.length();
        int n2 = s2.length();
        int n3 = s3.length();

        // Create a 3D array (dp) to store the LCS lengths
        // for each combination of substrings
        int[][][] dp = new int[n1 + 1][n2 + 1][n3 + 1];

        // dp[i][j][k] contains length of LCS of s1[0..i-1],
        // s2[0..j-1], and s3[0..k-1]
        for (int i = 0; i <= n1; i++) {
            for (int j = 0; j <= n2; j++) {
                for (int k = 0; k <= n3; k++) {
                    if (i == 0 || j == 0 || k == 0) {
                        // Base Case: any string is empty
                        dp[i][j][k] = 0; 
                    }
                    else if (s1.charAt(i - 1) == s2.charAt(j - 1)
                             && s1.charAt(i - 1) == s3.charAt(k - 1)) {
                                 
                        dp[i][j][k]= dp[i - 1][j - 1][k - 1]+ 1;  
                    }
                    else {
                        dp[i][j][k] = Math.max(Math.max(dp[i - 1][j][k],
                                      dp[i][j - 1][k]),dp[i][j][k - 1]);  
                    }
                }
            }
        }

        // dp[n1][n2][n3] contains length of LCS for
        // s1[0..n1-1], s2[0..n2-1], and s3[0..n3-1]
        return dp[n1][n2][n3];
    }

    public static void main(String[] args) {
        String s1 = "AGGT12";
        String s2 = "12TXAYB";
        String s3 = "12XBA";
        int res = lcsOf3(s1, s2, s3);
        System.out.print(res);
    }
}
Python
# Python program to find the Longest Common Subsequence of
# three string using tabulation

def lcsOf3(s1, s2, s3):
    n1 = len(s1)
    n2 = len(s2)
    n3 = len(s3)

    # Create a 3D array (dp) to store
    # the LCS lengths for each combination of substrings
    dp = [[[0 for _ in range(n3 + 1)] for _ in range(n2 + 1)]
          for _ in range(n1 + 1)]

    # dp[i][j][k] contains length of LCS of s1[0..i-1],
    # s2[0..j-1], and s3[0..k-1]
    for i in range(n1 + 1):
        for j in range(n2 + 1):
            for k in range(n3 + 1):
                if i == 0 or j == 0 or k == 0:
                    dp[i][j][k] = 0  
                elif s1[i - 1] == s2[j - 1] and s1[i - 1] == s3[k - 1]:
                    dp[i][j][k] = dp[i - 1][j - 1][k - 1] + \
                        1  
                else:
                   
                    dp[i][j][k] = max(dp[i - 1][j][k], dp[i]
                                      [j - 1][k], dp[i][j][k - 1])

    # dp[n1][n2][n3] contains length of LCS for
    # s1[0..n1-1], s2[0..n2-1], and s3[0..n3-1]
    return dp[n1][n2][n3]


if __name__ == "__main__":
    s1 = "AGGT12"
    s2 = "12TXAYB"
    s3 = "12XBA"
    res = lcsOf3(s1, s2, s3)
    print(res)
C#
// C# program to find the Longest Common Subsequence of
// three string using tabulation

using System;

class GfG {
     
    static int lcsOf3(string s1, string s2, string s3) {
        int n1 = s1.Length;
        int n2 = s2.Length;
        int n3 = s3.Length;

        // Create a 3D array (dp) to store the LCS lengths
        // for each combination of substrings
        int[, , ] dp = new int[n1 + 1, n2 + 1, n3 + 1];

        // dp[i, j, k] contains length of LCS of s1[0..i-1],
        // s2[0..j-1], and s3[0..k-1]
        for (int i = 0; i <= n1; i++) {
            for (int j = 0; j <= n2; j++) {
                for (int k = 0; k <= n3; k++) {
                    if (i == 0 || j == 0 || k == 0)
                        dp[i, j, k] = 0;  
                                         
                    else if (s1[i - 1] == s2[j - 1]
                             && s1[i - 1] == s3[k - 1])
                        dp[i, j, k]
                            = dp[i - 1, j - 1, k - 1]
                              + 1;  
                    else
                        dp[i, j, k] = Math.Max(
                            Math.Max(dp[i - 1, j, k],dp[i, j - 1, k]),
                            dp[i, j,k - 1]);  
                                       
                }
            }
        }

        // dp[n1, n2, n3] contains the length of LCS for
        // s1[0..n1-1], s2[0..n2-1], and s3[0..n3-1]
        return dp[n1, n2, n3];
    }

    
    static void Main(string[] args) {
        string s1 = "AGGT12";
        string s2 = "12TXAYB";
        string s3 = "12XBA";
        int res = lcsOf3(s1, s2, s3);
        Console.WriteLine(res);
    }
}
JavaScript
// JavaScript program to find the Longest Common Subsequence of
// three string using tabulation
 
function lcsOf3(s1, s2, s3) {
    const n1 = s1.length;
    const n2 = s2.length;
    const n3 = s3.length;

    // Create a 3D array (dp) to store the LCS lengths for
    // each combination of substrings
    let dp = Array.from(
        {length : n1 + 1},
        () => Array.from({length : n2 + 1},
                         () => Array(n3 + 1).fill(0)));

    // dp[i][j][k] contains length of LCS of s1[0..i-1],
    // s2[0..j-1], and s3[0..k-1]
    for (let i = 0; i <= n1; i++) {
        for (let j = 0; j <= n2; j++) {
            for (let k = 0; k <= n3; k++) {
                if (i === 0 || j === 0 || k === 0) {
                
                // Base case: any string is empty                 
                    dp[i][j][k] = 0;  
                }
                else if (s1[i - 1] === s2[j - 1]
                         && s1[i - 1] === s3[k - 1]) {
                    dp[i][j][k] = dp[i - 1][j - 1][k - 1]
                                  + 1;  
                }
                else {
                    dp[i][j][k] = Math.max(
                        Math.max(dp[i - 1][j][k],
                                 dp[i][j - 1][k]),
                        dp[i][j][k - 1]);  
                }
            }
        }
    }

    // dp[n1][n2][n3] contains the length of LCS for
    // s1[0..n1-1], s2[0..n2-1], and s3[0..n3-1]
    return dp[n1][n2][n3];
}

const s1 = "AGGT12";
const s2 = "12TXAYB";
const s3 = "12XBA";
const res = lcsOf3(s1, s2, s3);
console.log(res);

Output
2

[Expected Approach] Space Optimized Bottom-Up DP – O(n1*n2*n3) Time and O(n2*n3) Space

We observe that in the original 3D DP approach, at each step i, we only rely on values from the previous layer i-1. Hence, instead of maintaining the full 3D DP table dp[i][j][k], we can optimize space by using only two 2D arrays: prev and curr, each of size (n2+1) × (n3+1). These arrays are updated iteratively for each i.

The transition state becomes:

if (s1[i-1] == s2[j-1] && s2[j-1] == s3[k-1])
curr[j][k] = 1 + prev[j-1][k-1];

else
curr[j][k] = max({prev[j][k], curr[j-1][k], curr[j][k-1]});

After processing all j and k, we set prev = curr and repeat. This reduces the space complexity from O(n1 × n2 × n3) to O(n2 × n3).

C++
// C++ program to find the Longest Common Subsequence of
// three strings using tabulation (space optimized)

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

// Function to compute LCS of three strings using 2D DP (space optimized)
int lcsOf3(string &s1, string &s2, string &s3){
    
    // Length of first string
    int n1 = s1.length(); 
    // Length of second string
    int n2 = s2.length(); 
    // Length of third string
    int n3 = s3.length(); 

    // Initialize two 2D arrays for DP:
    // prev holds values for previous i-1 level
    // curr holds values for current i level
    vector<vector<int>> prev(n2 + 1, vector<int>(n3 + 1, 0));
    vector<vector<int>> curr(n2 + 1, vector<int>(n3 + 1, 0));

    // Iterate over all characters of s1
    for (int i = 1; i <= n1; i++){
        
        // Iterate over all characters of s2
        for (int j = 1; j <= n2; j++){
            
            // Iterate over all characters of s3
            for (int k = 1; k <= n3; k++){
                
                // If current characters of all three strings match
                if (s1[i - 1] == s2[j - 1] && s2[j - 1] == s3[k - 1])
                    curr[j][k] = 1 + prev[j - 1][k - 1]; 
                else
                    // Take the maximum of excluding current 
                    // character from any one string
                    curr[j][k] = max({prev[j][k], curr[j - 1][k], curr[j][k - 1]});
            }
        }
        // Move curr to prev for the next iteration
        prev = curr;
    }

    // The result is in curr[n2][n3], which holds the final LCS length
    return curr[n2][n3];
}

int main(){
    
    string s1 = "AGGT12";
    string s2 = "12TXAYB";
    string s3 = "12XBA";

    // Compute and print the LCS of all three strings
    int res = lcsOf3(s1, s2, s3);
    cout << res << endl;

    return 0;
}
Java
class GfG {

    // Function to compute LCS of three strings using space-optimized DP
    static int lcsOf3(String s1, String s2, String s3) {
        int n1 = s1.length();
        int n2 = s2.length();
        int n3 = s3.length();

        // Create two 2D arrays for space-optimized DP
        int[][] prev = new int[n2 + 1][n3 + 1];
        int[][] curr = new int[n2 + 1][n3 + 1];

        // Iterate over all characters in s1
        for (int i = 1; i <= n1; i++) {
    
            // Iterate over all characters in s2
            for (int j = 1; j <= n2; j++) {
    
                // Iterate over all characters in s3
                for (int k = 1; k <= n3; k++) {
                    if (s1.charAt(i - 1) == s2.charAt(j - 1) &&
                        s2.charAt(j - 1) == s3.charAt(k - 1)) {
                        curr[j][k] = 1 + prev[j - 1][k - 1];
                    } else {
                        curr[j][k] = Math.max(prev[j][k], 
                                       Math.max(curr[j - 1][k], curr[j][k - 1]));
                    }
                }
            }
    
            // Copy current to previous for the next round
            for (int j = 0; j <= n2; j++) {
                System.arraycopy(curr[j], 0, prev[j], 0, n3 + 1);
            }
        }

        return curr[n2][n3];
    }

    public static void main(String[] args) {
        String s1 = "AGGT12";
        String s2 = "12TXAYB";
        String s3 = "12XBA";

        int result = lcsOf3(s1, s2, s3);
        System.out.println(result);
    }
}
Python
def lcsOf3(s1, s2, s3):
    
    # Lengths of the three strings
    n1 = len(s1)
    n2 = len(s2)
    n3 = len(s3)

    # Initialize two 2D DP arrays
    # prev holds values for the previous i-1 level
    # curr holds values for the current i level
    prev = [[0] * (n3 + 1) for _ in range(n2 + 1)]
    curr = [[0] * (n3 + 1) for _ in range(n2 + 1)]

    # Iterate over all characters of s1
    for i in range(1, n1 + 1):
    
        # Iterate over all characters of s2
        for j in range(1, n2 + 1):
    
            # Iterate over all characters of s3
            for k in range(1, n3 + 1):
    
                # If characters match in all three strings
                if s1[i - 1] == s2[j - 1] and s2[j - 1] == s3[k - 1]:
                    curr[j][k] = 1 + prev[j - 1][k - 1]
                else:
    
                    # Take max by excluding current char from one of the strings
                    curr[j][k] = max(prev[j][k], curr[j - 1][k],
                                     curr[j][k - 1])
        
        # Copy curr to prev for the next i-level iteration
        prev = [row[:] for row in curr]

    # The final LCS length is at curr[n2][n3]
    return curr[n2][n3]

if __name__ == "__main__":
    s1 = "AGGT12"
    s2 = "12TXAYB"
    s3 = "12XBA"
    
    # Call the function and print result
    res = lcsOf3(s1, s2, s3)
    print(res)
C#
using System;

class GfG{
    // Function to compute LCS of three strings using space-optimized DP
    static int lcsOf3(string s1, string s2, string s3){
        
        int n1 = s1.Length;
        int n2 = s2.Length;
        int n3 = s3.Length;

        // Create two 2D arrays for space-optimized DP
        int[,] prev = new int[n2 + 1, n3 + 1];
        int[,] curr = new int[n2 + 1, n3 + 1];

        // Iterate over all characters of s1
        for (int i = 1; i <= n1; i++){
            
            // Iterate over all characters of s2
            for (int j = 1; j <= n2; j++){
                
                // Iterate over all characters of s3
                for (int k = 1; k <= n3; k++){
                    
                    if (s1[i - 1] == s2[j - 1] && s2[j - 1] == s3[k - 1]){
                        curr[j, k] = 1 + prev[j - 1, k - 1];
                    }
                    else{
                        curr[j, k] = Math.Max(prev[j, k],
                                    Math.Max(curr[j - 1, k], curr[j, k - 1]));
                    }
                }
            }

            // Copy curr to prev for the next i
            for (int j = 0; j <= n2; j++)
                for (int k = 0; k <= n3; k++)
                    prev[j, k] = curr[j, k];
        }

        return curr[n2, n3];
    }

    static void Main() {
        
        string s1 = "AGGT12";
        string s2 = "12TXAYB";
        string s3 = "12XBA";

        int result = lcsOf3(s1, s2, s3);
        Console.WriteLine(result);
    }
}
JavaScript
function lcsOf3(s1, s2, s3) {
    // Lengths of the three strings
    const n1 = s1.length;
    const n2 = s2.length;
    const n3 = s3.length;

    // Initialize two 2D DP arrays:
    // prev stores values from the previous i-1 iteration
    // curr stores values for the current i iteration
    let prev = Array.from({ length: n2 + 1 }, () => Array(n3 + 1).fill(0));
    let curr = Array.from({ length: n2 + 1 }, () => Array(n3 + 1).fill(0));

    // Iterate over all characters of s1
    for (let i = 1; i <= n1; i++) {
        
        // Iterate over all characters of s2
        for (let j = 1; j <= n2; j++) {
        
            // Iterate over all characters of s3
            for (let k = 1; k <= n3; k++) {
                // If characters match in all three strings
        
                if (s1[i - 1] === s2[j - 1] && s2[j - 1] === s3[k - 1]) {
                    curr[j][k] = 1 + prev[j - 1][k - 1];
                } else {
                    // Take max by excluding current char from one of the strings
                    curr[j][k] = Math.max(prev[j][k], curr[j - 1][k],
                                          curr[j][k - 1]);
                }
            }
        }
        prev = curr.map(row => row.slice());
    }

    // The final result (LCS length) is at curr[n2][n3]
    return curr[n2][n3];
}

// Driver Code
const s1 = "AGGT12";
const s2 = "12TXAYB";
const s3 = "12XBA";

// Call the function and log result
const res = lcsOf3(s1, s2, s3);
console.log(res);

Output
2



Next Article

Similar Reads