LCS (Longest Common Subsequence) of three strings
Last Updated :
23 Jul, 2025
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 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:
- 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);
[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);
[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);
[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);
Similar Reads
Basics & Prerequisites
Data Structures
Array Data StructureIn this article, we introduce array, implementation in different popular languages, its basic operations and commonly seen problems / interview questions. An array stores items (in case of C/C++ and Java Primitive Arrays) or their references (in case of Python, JS, Java Non-Primitive) at contiguous
3 min read
String in Data StructureA string is a sequence of characters. The following facts make string an interesting data structure.Small set of elements. Unlike normal array, strings typically have smaller set of items. For example, lowercase English alphabet has only 26 characters. ASCII has only 256 characters.Strings are immut
2 min read
Hashing in Data StructureHashing is a technique used in data structures that efficiently stores and retrieves data in a way that allows for quick access. Hashing involves mapping data to a specific index in a hash table (an array of items) using a hash function. It enables fast retrieval of information based on its key. The
2 min read
Linked List Data StructureA linked list is a fundamental data structure in computer science. It mainly allows efficient insertion and deletion operations compared to arrays. Like arrays, it is also used to implement other data structures like stack, queue and deque. Hereâs the comparison of Linked List vs Arrays Linked List:
2 min read
Stack Data StructureA Stack is a linear data structure that follows a particular order in which the operations are performed. The order may be LIFO(Last In First Out) or FILO(First In Last Out). LIFO implies that the element that is inserted last, comes out first and FILO implies that the element that is inserted first
2 min read
Queue Data StructureA Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific order. It follows the principle of "First in, First out" (FIFO), where the first element added to the queue is the first one to be removed. It is used as a buffer in computer systems
2 min read
Tree Data StructureTree Data Structure is a non-linear data structure in which a collection of elements known as nodes are connected to each other via edges such that there exists exactly one path between any two nodes. Types of TreeBinary Tree : Every node has at most two childrenTernary Tree : Every node has at most
4 min read
Graph Data StructureGraph Data Structure is a collection of nodes connected by edges. It's used to represent relationships between different entities. If you are looking for topic-wise list of problems on different topics like DFS, BFS, Topological Sort, Shortest Path, etc., please refer to Graph Algorithms. Basics of
3 min read
Trie Data StructureThe Trie data structure is a tree-like structure used for storing a dynamic set of strings. It allows for efficient retrieval and storage of keys, making it highly effective in handling large datasets. Trie supports operations such as insertion, search, deletion of keys, and prefix searches. In this
15+ min read
Algorithms
Searching AlgorithmsSearching algorithms are essential tools in computer science used to locate specific items within a collection of data. In this tutorial, we are mainly going to focus upon searching in an array. When we search an item in an array, there are two most common algorithms used based on the type of input
2 min read
Sorting AlgorithmsA Sorting Algorithm is used to rearrange a given array or list of elements in an order. For example, a given array [10, 20, 5, 2] becomes [2, 5, 10, 20] after sorting in increasing order and becomes [20, 10, 5, 2] after sorting in decreasing order. There exist different sorting algorithms for differ
3 min read
Introduction to RecursionThe process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. A recursive algorithm takes one step toward solution and then recursively call itself to further move. The algorithm stops once we reach the solution
14 min read
Greedy AlgorithmsGreedy algorithms are a class of algorithms that make locally optimal choices at each step with the hope of finding a global optimum solution. At every step of the algorithm, we make a choice that looks the best at the moment. To make the choice, we sometimes sort the array so that we can always get
3 min read
Graph AlgorithmsGraph is a non-linear data structure like tree data structure. The limitation of tree is, it can only represent hierarchical data. For situations where nodes or vertices are randomly connected with each other other, we use Graph. Example situations where we use graph data structure are, a social net
3 min read
Dynamic Programming or DPDynamic Programming is an algorithmic technique with the following properties.It is mainly an optimization over plain recursion. Wherever we see a recursive solution that has repeated calls for the same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the results of
3 min read
Bitwise AlgorithmsBitwise algorithms in Data Structures and Algorithms (DSA) involve manipulating individual bits of binary representations of numbers to perform operations efficiently. These algorithms utilize bitwise operators like AND, OR, XOR, NOT, Left Shift, and Right Shift.BasicsIntroduction to Bitwise Algorit
4 min read
Advanced
Segment TreeSegment Tree is a data structure that allows efficient querying and updating of intervals or segments of an array. It is particularly useful for problems involving range queries, such as finding the sum, minimum, maximum, or any other operation over a specific range of elements in an array. The tree
3 min read
Pattern SearchingPattern searching algorithms are essential tools in computer science and data processing. These algorithms are designed to efficiently find a particular pattern within a larger set of data. Patten SearchingImportant Pattern Searching Algorithms:Naive String Matching : A Simple Algorithm that works i
2 min read
GeometryGeometry is a branch of mathematics that studies the properties, measurements, and relationships of points, lines, angles, surfaces, and solids. From basic lines and angles to complex structures, it helps us understand the world around us.Geometry for Students and BeginnersThis section covers key br
2 min read
Interview Preparation
Practice Problem