Friday, November 15, 2024
Google search engine
HomeLanguagesDynamic ProgrammingA Space Optimized Solution of LCS

A Space Optimized Solution of LCS

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>


Output

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.


Output

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.

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

RELATED ARTICLES

Most Popular

Recent Comments