Given two strings, find the length of the longest subsequence present in both of them.
Examples:
LCS for input Sequences “ABCDGH” and “AEDFHR” is “ADH” of length 3. LCS for input Sequences “AGGTAB” and “GXTXAYB” is “GTAB” of length 4.
We have discussed a typical dynamic programming-based solution for LCS. We can optimize the space used by LCS problem. We know the recurrence relationship of the LCS problem is
CPP
/* Returns length of LCS for X[0..m-1], Y[0..n-1] */ int lcs(string &X, string &Y) { int m = X.length(), n = Y.length(); int L[m+1][n+1]; /* Following steps build L[m+1][n+1] in bottom up fashion. Note that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1] */ for ( int i=0; i<=m; i++) { for ( int j=0; j<=n; j++) { if (i == 0 || j == 0) L[i][j] = 0; else if (X[i-1] == Y[j-1]) L[i][j] = L[i-1][j-1] + 1; else L[i][j] = max(L[i-1][j], L[i][j-1]); } } /* L[m][n] contains length of LCS for X[0..n-1] and Y[0..m-1] */ return L[m][n]; } |
Java
import java.io.*; class GFG { // Returns length of LCS for X[0..m-1], Y[0..n-1] public static int lcs(String X, String Y) { // Find lengths of two strings int m = X.length(), n = Y.length(); int L[][] = new int [m + 1 ][n + 1 ]; /* Following steps build L[m+1][n+1] in bottom up fashion. Note that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1] */ for ( int i = 0 ; i <= m; i++) { for ( int j = 0 ; j <= n; j++) { if (i == 0 || j == 0 ) L[i][j] = 0 ; else if (X[i - 1 ] == Y[j - 1 ]) L[i][j] = L[i - 1 ][j - 1 ] + 1 ; else L[i][j] = max(L[i - 1 ][j], L[i][j - 1 ]); } } /* L[m][n] contains length of LCS for X[0..n-1] and Y[0..m-1] */ return L[m][n]; } } // This code is contributed by rajsanghavi9. |
C#
// C# program to implement // the above approach using System; class GFG{ // Returns length of LCS for X[0..m-1], Y[0..n-1] public static int lcs( string X, string Y) { // Find lengths of two strings int m = X.Length, n = Y.Length; int [,] L = new int [m + 1, n + 1]; /* Following steps build L[m+1][n+1] in bottom up fashion. Note that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1] */ for ( int i = 0; i <= m; i++) { for ( int j = 0; j <= n; j++) { if (i == 0 || j == 0) L[i, j] = 0; else if (X[i - 1] == Y[j - 1]) L[i, j] = L[i - 1, j - 1] + 1; else L[i, j] = Math.Max(L[i - 1, j], L[i, j - 1]); } } /* L[m][n] contains length of LCS for X[0..n-1] and Y[0..m-1] */ return L[m, n]; } } // this code is contributed by code_hunt. |
Javascript
<script> // Dynamic Programming Java implementation of LCS problem // Utility function to get max of 2 integers function max(a, b) { if (a > b) return a; else return b; } // Returns length of LCS for X[0..m-1], Y[0..n-1] function lcs(X, Y, m, n) { var L = new Array(m + 1); for ( var i = 0; i < L.length; i++) { L[i] = new Array(n + 1); } var i, j; /* Following steps build L[m+1][n+1] in bottom up fashion. Note that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1] */ for (i = 0; i <= m; i++) { for (j = 0; j <= n; j++) { if (i == 0 || j == 0) L[i][j] = 0; else if (X[i - 1] == Y[j - 1]) L[i][j] = L[i - 1][j - 1] + 1; else L[i][j] = max(L[i - 1][j], L[i][j - 1]); } } /* L[m][n] contains length of LCS for X[0..n-1] and Y[0..m-1] */ return L[m][n]; } // This code is contributed by akshitsaxenaa09. </script> |
Python3
# Returns length of LCS for X[0..m-1], Y[0..n-1] def lcs(X, Y): m = len (X) n = len (Y) L = [[ 0 for j in range (n + 1 )] for i in range (m + 1 )] '''Following steps build L[m+1][n+1] in bottom up fashion. Note that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1]''' for i in range (m + 1 ): for j in range (n + 1 ): if i = = 0 or j = = 0 : L[i][j] = 0 elif X[i - 1 ] = = Y[j - 1 ]: L[i][j] = L[i - 1 ][j - 1 ] + 1 else : L[i][j] = max (L[i - 1 ][j], L[i][j - 1 ]) # L[m][n] contains length of LCS for X[0..n-1] and Y[0..m-1] return L[m][n] # This code is contributed by Susobhan Akhuli |
How to find the length of LCS is O(n) auxiliary space?
We strongly recommend that you click here and practice it, before moving on to the solution.
One important observation in the above simple implementation is, in each iteration of the outer loop we only need values from all columns of the previous row. So there is no need to store all rows in our DP matrix, we can just store two rows at a time and use them. In that way, used space will be reduced from L[m+1][n+1] to L[2][n+1]. Below is the implementation of the above idea.
C++
// Space optimized C++ implementation // of LCS problem #include<bits/stdc++.h> using namespace std; // Returns length of LCS // for X[0..m-1], Y[0..n-1] int lcs(string &X, string &Y) { // Find lengths of two strings int m = X.length(), n = Y.length(); int L[2][n + 1]; // Binary index, used to // index current row and // previous row. bool bi; for ( int i = 0; i <= m; i++) { // Compute current // binary index bi = i & 1; for ( int j = 0; j <= n; j++) { if (i == 0 || j == 0) L[bi][j] = 0; else if (X[i-1] == Y[j-1]) L[bi][j] = L[1 - bi][j - 1] + 1; else L[bi][j] = max(L[1 - bi][j], L[bi][j - 1]); } } // Last filled entry contains // length of LCS // for X[0..n-1] and Y[0..m-1] return L[bi][n]; } // Driver code int main() { string X = "AGGTAB" ; string Y = "GXTXAYB" ; printf ( "Length of LCS is %d\n" , lcs(X, Y)); return 0; } |
Java
// Java Code for A Space Optimized // Solution of LCS import java.io.*; class GFG { // Returns length of LCS // for X[0..m - 1], // Y[0..n - 1] public static int lcs(String X, String Y) { // Find lengths of two strings int m = X.length(), n = Y.length(); int L[][] = new int [ 2 ][n + 1 ]; // Binary index, used to index // current row and previous row. int bi = 0 ; for ( int i = 0 ; i <= m; i++) { // Compute current binary index bi = i & 1 ; for ( int j = 0 ; j <= n; j++) { if (i == 0 || j == 0 ) L[bi][j] = 0 ; else if (X.charAt(i - 1 ) == Y.charAt(j - 1 )) L[bi][j] = L[ 1 - bi][j - 1 ] + 1 ; else L[bi][j] = Math.max(L[ 1 - bi][j], L[bi][j - 1 ]); } } // Last filled entry contains length of // LCS for X[0..n-1] and Y[0..m-1] return L[bi][n]; } // Driver Code public static void main(String[] args) { String X = "AGGTAB" ; String Y = "GXTXAYB" ; System.out.println( "Length of LCS is " + lcs(X, Y)); } } // This code is contributed by Arnav Kr. Mandal. |
Python3
# Space optimized Python # implementation of LCS problem # Returns length of LCS for # X[0..m-1], Y[0..n-1] def lcs(X, Y): # Find lengths of two strings m = len (X) n = len (Y) L = [[ 0 for i in range (n + 1 )] for j in range ( 2 )] # Binary index, used to index current row and # previous row. bi = bool for i in range (m): # Compute current binary index bi = i& 1 for j in range (n + 1 ): if (i = = 0 or j = = 0 ): L[bi][j] = 0 elif (X[i] = = Y[j - 1 ]): L[bi][j] = L[ 1 - bi][j - 1 ] + 1 else : L[bi][j] = max (L[ 1 - bi][j], L[bi][j - 1 ]) # Last filled entry contains length of LCS # for X[0..n-1] and Y[0..m-1] return L[bi][n] # Driver Code X = "AGGTAB" Y = "GXTXAYB" print ( "Length of LCS is" , lcs(X, Y)) # This code is contributed by Soumen Ghosh. |
C#
// C# Code for A Space // Optimized Solution of LCS using System; class GFG { // Returns length of LCS // for X[0..m - 1], // Y[0..n - 1] public static int lcs( string X, string Y) { // Find lengths of // two strings int m = X.Length, n = Y.Length; int [,]L = new int [2, n + 1]; // Binary index, used to // index current row and // previous row. int bi = 0; for ( int i = 0; i <= m; i++) { // Compute current // binary index bi = i & 1; for ( int j = 0; j <= n; j++) { if (i == 0 || j == 0) L[bi, j] = 0; else if (X[i - 1] == Y[j - 1]) L[bi, j] = L[1 - bi, j - 1] + 1; else L[bi, j] = Math.Max(L[1 - bi, j], L[bi, j - 1]); } } // Last filled entry contains // length of LCS for X[0..n-1] // and Y[0..m-1] return L[bi, n]; } // Driver Code public static void Main() { string X = "AGGTAB" ; string Y = "GXTXAYB" ; Console.Write( "Length of LCS is " + lcs(X, Y)); } } // This code is contributed // by shiv_bhakt. |
PHP
<?php // Space optimized PHP implementation // of LCS problem // Returns length of LCS // for X[0..m-1], Y[0..n-1] function lcs( $X , $Y ) { // Find lengths of two strings $m = strlen ( $X ); $n = strlen ( $Y ); $L = array ( array ()); // Binary index, used to index // current row and previous row. for ( $i = 0; $i <= $m ; $i ++) { // Compute current binary index $bi = $i & 1; for ( $j = 0; $j <= $n ; $j ++) { if ( $i == 0 || $j == 0) $L [ $bi ][ $j ] = 0; else if ( $X [ $i - 1] == $Y [ $j - 1]) $L [ $bi ][ $j ] = $L [1 - $bi ][ $j - 1] + 1; else $L [ $bi ][ $j ] = max( $L [1 - $bi ][ $j ], $L [ $bi ][ $j - 1]); } } // Last filled entry contains // length of LCS // for X[0..n-1] and Y[0..m-1] return $L [ $bi ][ $n ]; } // Driver code $X = "AGGTAB" ; $Y = "GXTXAYB" ; echo "Length of LCS is : " , lcs( $X , $Y ); // This code is contributed by Ryuga ?> |
Javascript
<script> // Javascript Code for A Space Optimized Solution of LCS // Returns length of LCS // for X[0..m - 1], // Y[0..n - 1] function lcs(X, Y) { // Find lengths of two strings let m = X.length, n = Y.length; let L = new Array(2); for (let i = 0; i < 2; i++) { L[i] = new Array(n + 1); for (let j = 0; j < n + 1; j++) { L[i][j] = 0; } } // Binary index, used to index // current row and previous row. let bi=0; for (let i = 0; i <= m; i++) { // Compute current binary index bi = i & 1; for (let j = 0; j <= n; j++) { if (i == 0 || j == 0) L[bi][j] = 0; else if (X[i - 1] == Y[j - 1]) L[bi][j] = L[1 - bi][j - 1] + 1; else L[bi][j] = Math.max(L[1 - bi][j], L[bi][j - 1]); } } // Last filled entry contains length of // LCS for X[0..n-1] and Y[0..m-1] return L[bi][n]; } let X = "AGGTAB" ; let Y = "GXTXAYB" ; document.write( "Length of LCS is " + lcs(X, Y)); </script> |
Length of LCS is 4
Time Complexity : O(m*n)
Auxiliary Space: O(n)
We can further improve the space complexity of above program
C++
#include <iostream> using namespace std; // lcs with tabulation int lcs( const string& s1, const string& s2) { int m = s1.length(), n = s2.length(); int db[n + 1] = {}; // db is initialized to all zeros // i and j are the length of s1 and s2 for ( int i = 1; i <= m; ++i) { int prev = db[0]; for ( int j = 1; j <= n; ++j) { int temp = db[j]; if (s1[i - 1] == s2[j - 1]) db[j] = 1 + prev; else db[j] = max(db[j - 1], db[j]); prev = temp; } } return db[n]; } int main() { string s1 = "AGGTAB" , s2 = "GXTXAYB" ; int r = lcs(s1, s2); cout << "Length of LCS is " << lcs(s1, s2); return 0; } |
Java
/*package whatever //do not write package name here */ import java.io.*; class GFG { public static int lcs(String text1, String text2) { int [] dp = new int [text2.length()+ 1 ]; for ( int i = 0 ; i< text1.length(); i++){ int prev = dp[ 0 ]; for ( int j = 1 ; j < dp.length; j++){ int temp = dp[j]; if (text1.charAt(i) != text2.charAt(j- 1 )){ dp[j] = Math.max(dp[j- 1 ], dp[j]); } else { dp[j] = prev + 1 ; } prev = temp; } } return dp[dp.length- 1 ]; } public static void main(String[] args) { String X = "AGGTAB" ; String Y = "GXTXAYB" ; System.out.println( "Length of LCS is " + lcs(X, Y)); } } |
Python3
def lcs(text1, text2): m, n = len (text1), len (text2) if m > n : text1, text2 = text2, text1 dp = [ 0 ] * (n + 1 ) for c in text1: prev = 0 for i, d in enumerate (text2): prev, dp[i + 1 ] = dp[i + 1 ], prev + 1 if c = = d else max (dp[i], dp[i + 1 ]) return dp[ - 1 ] X = "AGGTAB" Y = "GXTXAYB" print ( "Length of LCS is" , lcs(X, Y)) # This code is contributed by Tushar Khera . |
C#
//C# code for the above approach using System; class GFG { public static int lcs( string text1, string text2) { //Initialize dp array int [] dp = new int [text2.Length + 1]; for ( int i = 0; i < text1.Length; i++) { int prev = dp[0]; for ( int j = 1; j < dp.Length; j++) { int temp = dp[j]; if (text1[i] != text2[j - 1]) { dp[j] = Math.Max(dp[j - 1], dp[j]); } else { dp[j] = prev + 1; } prev = temp; } } return dp[dp.Length - 1]; } //Driver code public static void Main( string [] args) { string X = "AGGTAB" ; string Y = "GXTXAYB" ; Console.WriteLine( "Length of LCS is " + lcs(X, Y)); } } |
Javascript
// Function to calculate the longest common subsequence using tabulation function lcs(s1, s2) { // Get the lengths of strings s1 and s2 let m = s1.length, n = s2.length; // Initialize an array of size n + 1 with all elements as 0 let db = Array(n + 1).fill(0); // Loop through the string s1 for (let i = 1; i <= m; ++i) { // Store the value of the current 0th index of db let prev = db[0]; // Loop through the string s2 for (let j = 1; j <= n; ++j) { // Store the current value of jth index of db let temp = db[j]; // Check if the current characters of s1 and s2 are equal if (s1[i - 1] === s2[j - 1]) // If equal, increase the length of the common subsequence db[j] = 1 + prev; else // If not equal, use the maximum length from the previous entries db[j] = Math.max(db[j - 1], db[j]); // Update the value of prev prev = temp; } } // Return the length of the longest common subsequence return db[n]; } // Example strings let s1 = "AGGTAB" , s2 = "GXTXAYB" ; // Calculate the length of the longest common subsequence let r = lcs(s1, s2); // Log the length of the LCS console.log( "Length of LCS is " + r); // This code is contributed by unstoppablepandu. |
Length of LCS is 4
Time Complexity : O(m*n)
Auxiliary Space: O(n) as Earlier is 2N space is used but complexity Remains same as Space complexity is doesn’t depend the no. to which n is multiply
This article is contributed Shivam Mittal. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!