LCS (Longest Common Subsequence) of three strings (original) (raw)

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.

Table of Content

[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:

**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 s1 , s2 , 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:

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

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

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);

`

[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:

**2. Overlapping Subproblems:

// 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>> &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>> memo = vector<vector<vector>>(n1 + 1, vector<vector>(n2 + 1, vector(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);

`

[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:

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);

`

[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);

`