Memoization (1D, 2D and 3D) - GeeksforGeeks

08 Nov, 2021
Most of the Dynamic Programming problems are solved in two ways:  
Tabulation: Bottom UpMemoization: Top Down
Tabulation: Bottom Up
Memoization: Top Down
One of the easier approaches to solve most of the problems in DP is to write the recursive code at first and then write the Bottom-up Tabulation Method or Top-down Memoization of the recursive function. The steps to write the DP solution of Top-down approach to any problem is to:  
Write the recursive codeMemoize the return value and use it to reduce recursive calls.
Write the recursive code
Memoize the return value and use it to reduce recursive calls.
1-D MemoizationThe first step will be to write the recursive code. In the program below, a program related to recursion where only one parameter changes its value has been shown. Since only one parameter is non-constant, this method is known as 1-D memoization. E.g., the Fibonacci series problem to find the N-th term in the Fibonacci series. The recursive approach has been discussed here.Given below is the recursive code to find the N-th term:  
C++
Java
Python3
C#
Javascript
PHP
// C++ program to find the Nth term// of Fibonacci series#include <bits/stdc++.h>using namespace std; // Fibonacci Series using Recursionint fib(int n){     // Base case    if (n <= 1)        return n;     // recursive calls    return fib(n - 1) + fib(n - 2);} // Driver Codeint main(){    int n = 6;    printf("%d", fib(n));    return 0;}
// Java program to find the// Nth term of Fibonacci seriesimport java.io.*; class GFG{     // Fibonacci Series// using Recursionstatic int fib(int n){     // Base case    if (n <= 1)        return n;     // recursive calls    return fib(n - 1) +           fib(n - 2);} // Driver Codepublic static void main (String[] args){    int n = 6;    System.out.println(fib(n));}} // This code is contributed// by ajit
# Python3 program to find the Nth term# of Fibonacci series # Fibonacci Series using Recursiondef fib(n):      # Base case    if (n <= 1):        return n     # recursive calls    return fib(n - 1) + fib(n - 2) # Driver Codeif __name__=='__main__':    n = 6    print (fib(n))  # This code is contributed by# Shivi_Aggarwal
// C# program to find// the Nth term of// Fibonacci seriesusing System; class GFG{     // Fibonacci Series// using Recursionstatic int fib(int n){    // Base case    if (n <= 1)        return n;     // recursive calls    return fib(n - 1) +           fib(n - 2);}// Driver Codestatic public void Main (){    int n = 6;    Console.WriteLine(fib(n));}} // This code is contributed// by akt_mit
<script>// Javascript program to find the Nth term// of Fibonacci series // Fibonacci Series using Recursionfunction fib(n){     // Base case    if (n <= 1)        return n;     // recursive calls    return fib(n - 1) + fib(n - 2);} // Driver Codelet n = 6;document.write(fib(n)); // This code is contributed by subhammahato348.</script>
<?php// PHP program to find// the Nth term of// Fibonacci series// using Recursion function fib($n){     // Base case    if ($n <= 1)        return $n;     // recursive calls    return fib($n - 1) +           fib($n - 2);} // Driver Code$n = 6;echo fib($n); // This code is contributed// by ajit?>
8
 
A common observation is that this implementation does a lot of repeated work (see the following recursion tree). So this will consume a lot of time for finding the N-th Fibonacci number if done.  
                            fib(5)   
                     /                 \        
               fib(4)                  fib(3)   
             /      \                /       \
         fib(3)      fib(2)         fib(2)    fib(1)
        /   \          /    \       /      \ 
  fib(2)   fib(1)  fib(1) fib(0) fib(1) fib(0)
  /    \ 
fib(1) fib(0) 

In the above tree fib(3), fib(2), fib(1), fib(0) all are called more then once.
The following problem has been solved using the Tabulation method. In the program below, the steps to write a Top-Down approach program have been explained. Some modifications in the recursive program will reduce the complexity of the program and give the desired result. If fib(x) has not occurred previously, then we store the value of fib(x) in an array term at index x and return term[x]. By memoizing the return value of fib(x) at index x of an array, reduce the number of recursive calls at the next step when fib(x) has already been called. So without doing further recursive calls to compute the value of fib(x), return term[x] when fib(x) has already been computed previously to avoid a lot of repeated work as shown in the tree. Given below is the memoized recursive code to find the N-th term.  
C++
Java
Python3
C#
Javascript
// CPP program to find the Nth term// of Fibonacci series#include <bits/stdc++.h>using namespace std;int term[1000];// Fibonacci Series using memoized Recursionint fib(int n){    // base case    if (n <= 1)        return n;     // if fib(n) has already been computed    // we do not do further recursive calls    // and hence reduce the number of repeated    // work    if (term[n] != 0)        return term[n];     else {         // store the computed value of fib(n)        // in an array term at index n to        // so that it does not needs to be        // precomputed again        term[n] = fib(n - 1) + fib(n - 2);         return term[n];    }} // Driver Codeint main(){    int n = 6;    printf("%d", fib(n));    return 0;}
// Java program to find// the Nth term of// Fibonacci seriesimport java.io.*; class GFG{ static  int []term = new int [1000];// Fibonacci Series using// memoized Recursionstatic int fib(int n){    // base case    if (n <= 1)        return n;     // if fib(n) has already    // been computed we do not    // do further recursive    // calls and hence reduce    // the number of repeated    // work    if (term[n] != 0)        return term[n];     else    {         // store the computed value        // of fib(n) in an array        // term at index n to so that        // it does not needs to be        // precomputed again        term[n] = fib(n - 1) +                  fib(n - 2);         return term[n];    }} // Driver Codepublic static void main (String[] args){    int n = 6;    System.out.println(fib(n));}} // This code is contributed by ajit
# Python program to find the Nth term# of Fibonacci seriesterm = [0 for i in range(1000)] # Fibonacci Series using memoized Recursiondef fib(n):     # base case  if n <= 1:    return n   # if fib(n) has already been computed  # we do not do further recursive calls  # and hence reduce the number of repeated  # work  if term[n] != 0:    return term[n]   else:         # store the computed value of fib(n)    # in an array term at index n to    # so that it does not needs to be    # precomputed again    term[n] = fib(n - 1) + fib(n - 2)    return term[n] # Driver Coden = 6print(fib(n)) # This code is contributed by rohitsingh07052
// C# program to find// the Nth term of// Fibonacci series using System;class GFG{      // Fibonacci Series using// memoized Recursionstatic int fib(int n){    int[] term = new int [1000];          // base case    if (n <= 1)        return n;      // if fib(n) has already    // been computed we do not    // do further recursive    // calls and hence reduce    // the number of repeated    // work    if (term[n] != 0)        return term[n];      else    {          // store the computed value        // of fib(n) in an array        // term at index n to so that        // it does not needs to be        // precomputed again        term[n] = fib(n - 1) +                  fib(n - 2);          return term[n];    }}  // Driver Codepublic static void Main (){    int n = 6;    Console.Write(fib(n));}}
<script>    // Javascript program to find    // the Nth term of    // Fibonacci series         // Fibonacci Series using    // memoized Recursion    function fib(n)    {        let term = new Array(1000);        term.fill(0);         // base case        if (n <= 1)            return n;         // if fib(n) has already        // been computed we do not        // do further recursive        // calls and hence reduce        // the number of repeated        // work        if (term[n] != 0)            return term[n];         else        {             // store the computed value            // of fib(n) in an array            // term at index n to so that            // it does not needs to be            // precomputed again            term[n] = fib(n - 1) +                      fib(n - 2);             return term[n];        }    }     let n = 6;    document.write(fib(n));         // This code is contributed by mukesh07.</script>
8
 
If the recursive code has been written once, then memoization is just modifying the recursive program and storing the return values to avoid repetitive calls of functions that have been computed previously. 
2-D MemoizationIn the above program, the recursive function had only one argument whose value was not constant after every function call. Below, an implementation where the recursive program has two non-constant arguments has been shown. For e.g., Program to solve the standard Dynamic Problem LCS problem when two strings are given. The general recursive solution of the problem is to generate all subsequences of both given sequences and find the longest matching subsequence. The total possible combinations will be 2n. Hence, the recursive solution will take O(2n). The approach to writing the recursive solution has been discussed here. Given below is the recursive solution to the LCS problem: 
C++
Java
Python3
C#
Javascript
// A Naive recursive implementation of LCS problem#include <bits/stdc++.h> int max(int a, int b); // Returns length of LCS for X[0..m-1], Y[0..n-1]int lcs(char* X, char* Y, int m, int n){    if (m == 0 || n == 0)        return 0;    if (X[m - 1] == Y[n - 1])        return 1 + lcs(X, Y, m - 1, n - 1);    else        return max(lcs(X, Y, m, n - 1),                  lcs(X, Y, m - 1, n));} // Utility function to get max of 2 integersint max(int a, int b){    return (a > b) ? a : b;} // Driver Codeint main(){    char X[] = "AGGTAB";    char Y[] = "GXTXAYB";     int m = strlen(X);    int n = strlen(Y);     printf("Length of LCS is %dn", lcs(X, Y, m, n));     return 0;}
// A Naive recursive implementation of LCS problemimport java.io.*;class GFG{     // Utility function to get max of 2 integers    static int max(int a, int b) { return (a > b) ? a : b; }     // Returns length of LCS for X[0..m-1], Y[0..n-1]    static int lcs(String X, String Y, int m, int n)    {        if (m == 0 || n == 0)            return 0;        if (X.charAt(m - 1) == Y.charAt(n - 1))            return 1 + lcs(X, Y, m - 1, n - 1);        else            return max(lcs(X, Y, m, n - 1),                       lcs(X, Y, m - 1, n));    }     // Driver Code    public static void main(String[] args)    {        String X = "AGGTAB";        String Y = "GXTXAYB";         int m = X.length();        int n = Y.length();         System.out.print("Length of LCS is "                         + lcs(X, Y, m, n));    }} // This code is contributed by subhammahato348
# A Naive recursive implementation of LCS problem # Returns length of LCS for X[0..m-1], Y[0..n-1]def lcs(X, Y, m, n):    if (m == 0 or n == 0):        return 0;    if (X[m - 1] == Y[n - 1]):        return 1 + lcs(X, Y, m - 1, n - 1);    else:        return max(lcs(X, Y, m, n - 1),                  lcs(X, Y, m - 1, n)); # Driver Codeif __name__=='__main__':    X = "AGGTAB";    Y = "GXTXAYB";    m = len(X);    n = len(Y);    print("Length of LCS is {}n".format(lcs(X, Y, m, n))) # This code is contributed by rutvik_56.
// A Naive recursive implementation of LCS problemusing System;class GFG{   // Utility function to get max of 2 integers  static int max(int a, int b) { return (a > b) ? a : b; }   // Returns length of LCS for X[0..m-1], Y[0..n-1]  static int lcs(string X, string Y, int m, int n)  {    if (m == 0 || n == 0)      return 0;    if (X[m - 1] == Y[n - 1])      return 1 + lcs(X, Y, m - 1, n - 1);    else      return max(lcs(X, Y, m, n - 1),                 lcs(X, Y, m - 1, n));  }   // Driver Code  public static void Main()  {    string X = "AGGTAB";    string Y = "GXTXAYB";     int m = X.Length;    int n = Y.Length;     Console.Write("Length of LCS is "                  + lcs(X, Y, m, n));  }} // This code is contributed by subhammahato348
<script>// A Naive recursive implementation of LCS problem     // Utility function to get max of 2 integers    function max(a,b)    {         return (a > b) ? a : b;    }         // Returns length of LCS for X[0..m-1], Y[0..n-1]    function lcs(X,Y,m,n)    {        if (m == 0 || n == 0)            return 0;        if (X[m-1] == Y[n-1])            return 1 + lcs(X, Y, m - 1, n - 1);        else            return max(lcs(X, Y, m, n - 1),                       lcs(X, Y, m - 1, n));    }         // Driver Code    let X = "AGGTAB";    let Y = "GXTXAYB";    let m = X.length;    let n = Y.length;    document.write("Length of LCS is "                         + lcs(X, Y, m, n));           // This code is contributed by avanitrachhadiya2155</script>
Output:
Length of LCS is 4
Considering the above implementation, the following is a partial recursion tree for input strings “AXYT” and “AYZX”  
                  lcs("AXYT", "AYZX")
                       /                 \
         lcs("AXY", "AYZX")            lcs("AXYT", "AYZ")
         /           \                   /               \
lcs("AX", "AYZX") lcs("AXY", "AYZ")   lcs("AXY", "AYZ") lcs("AXYT", "AY")
In the above partial recursion tree, lcs(“AXY”, “AYZ”) is being solved twice. On drawing the complete recursion tree, it has been observed that there are many subproblems that are solved again and again. So this problem has Overlapping Substructure property and recomputation of same subproblems can be avoided by either using Memoization or Tabulation. The tabulation method has been discussed here. A common point of observation to use memoization in the recursive code will be the two non-constant arguments M and N in every function call. The function has 4 arguments, but 2 arguments are constant which does not affect the Memoization. The repetitive calls occur for N and M which have been called previously. So use a 2-D array to store the computed lcs(m, n) value at arr[m-1][n-1] as the string index starts from 0. Whenever the function with the same argument m and n are called again, we do not perform any further recursive call and return arr[m-1][n-1] as the previous computation of the lcs(m, n) has already been stored in arr[m-1][n-1], hence reducing the recursive calls that happen more than once. Below is the implementation of the Memoization approach of the recursive code.  
C++
Java
Python3
C#
Javascript
// C++ program to memoize// recursive implementation of LCS problem#include <bits/stdc++.h>int arr[1000][1000];int max(int a, int b); // Returns length of LCS for X[0..m-1], Y[0..n-1] */// memoization applied in recursive solutionint lcs(char* X, char* Y, int m, int n){    // base case    if (m == 0 || n == 0)        return 0;     // if the same state has already been    // computed    if (arr[m - 1][n - 1] != -1)        return arr[m - 1][n - 1];     // if equal, then we store the value of the    // function call    if (X[m - 1] == Y[n - 1]) {         // store it in arr to avoid further repetitive        // work in future function calls        arr[m - 1][n - 1] = 1 + lcs(X, Y, m - 1, n - 1);        return arr[m - 1][n - 1];    }    else {        // store it in arr to avoid further repetitive        // work in future function calls        arr[m - 1][n - 1] = max(lcs(X, Y, m, n - 1),                                lcs(X, Y, m - 1, n));        return arr[m - 1][n - 1];    }} // Utility function to get max of 2 integersint max(int a, int b){    return (a > b) ? a : b;} // Driver Codeint main(){    memset(arr, -1, sizeof(arr));    char X[] = "AGGTAB";    char Y[] = "GXTXAYB";     int m = strlen(X);    int n = strlen(Y);     printf("Length of LCS is %d", lcs(X, Y, m, n));     return 0;}
// Java program to memoize// recursive implementation of LCS problemimport java.io.*;import java.lang.*;class GFG{  public static int arr[][] = new int[1000][1000];   // Returns length of LCS for X[0..m-1], Y[0..n-1] */  // memoization applied in recursive solution  public static int lcs(String X, String Y, int m, int n)  {     // base case    if (m == 0 || n == 0)      return 0;     // if the same state has already been    // computed    if (arr[m - 1][n - 1] != -1)      return arr[m - 1][n - 1];     // if equal, then we store the value of the    // function call    if ( X.charAt(m - 1) == Y.charAt(n - 1))    {       // store it in arr to avoid further repetitive      // work in future function calls      arr[m - 1][n - 1] = 1 + lcs(X, Y, m - 1, n - 1);      return arr[m - 1][n - 1];    }    else    {       // store it in arr to avoid further repetitive      // work in future function calls      arr[m - 1][n - 1] = max(lcs(X, Y, m, n - 1),                              lcs(X, Y, m - 1, n));      return arr[m - 1][n - 1];    }  }   // Utility function to get max of 2 integers  public static int max(int a, int b)  {    return (a > b) ? a : b;  }   // Driver code  public static void main (String[] args)  {    for(int i = 0; i < 1000; i++)    {      for(int j = 0; j < 1000; j++)      {        arr[i][j] = -1;      }    }    String X = "AGGTAB";    String Y = "GXTXAYB";     int m = X.length();    int n = Y.length();     System.out.println("Length of LCS is " + lcs(X, Y, m, n));  }} // This code is contributed by manupathria.
# Python3 program to memoize# recursive implementation of LCS problem # Returns length of LCS for X[0..m-1], Y[0..n-1]# memoization applied in recursive solutiondef lcs(X, Y, m, n):     global arr     # base case    if (m == 0 or n == 0):        return 0     # if the same state has already been    # computed    if (arr[m - 1][n - 1] != -1):        return arr[m - 1][n - 1]     # if equal, then we store the value of the    # function call    if (X[m - 1] == Y[n - 1]):         # store it in arr to avoid further repetitive        # work in future function calls        arr[m - 1][n - 1] = 1 + lcs(X, Y, m - 1, n - 1)        return arr[m - 1][n - 1]     else:         # store it in arr to avoid further repetitive        # work in future function calls        arr[m - 1][n - 1] = max(lcs(X, Y, m, n - 1),                                lcs(X, Y, m - 1, n))        return arr[m - 1][n - 1]  # Driver code arr = [[0]*1000]*1000 for i in range(0, 1000):    for j in range(0, 1000):        arr[i][j] = -1 X = "AGGTAB"Y = "GXTXAYB" m = len(X)n = len(Y) print("Length of LCS is ", lcs(X, Y, m, n)) # This code is contributed by Dharanendra L V.
// C# program to memoize// recursive implementation of LCS problemusing System;public class GFG{   public static int[, ] arr = new int[1000, 1000];   // Returns length of LCS for X[0..m-1], Y[0..n-1] */  // memoization applied in recursive solution  public static int lcs(String X, String Y, int m, int n)  {     // base case    if (m == 0 || n == 0)      return 0;     // if the same state has already been    // computed    if (arr[m - 1, n - 1] != -1)      return arr[m - 1, n - 1];     // if equal, then we store the value of the    // function call    if ( X[m - 1] == Y[n - 1])    {       // store it in arr to avoid further repetitive      // work in future function calls      arr[m - 1, n - 1] = 1 + lcs(X, Y, m - 1, n - 1);      return arr[m - 1, n - 1];    }    else    {       // store it in arr to avoid further repetitive      // work in future function calls      arr[m - 1, n - 1] = max(lcs(X, Y, m, n - 1),                              lcs(X, Y, m - 1, n));      return arr[m - 1, n - 1];    }  }   // Utility function to get max of 2 integers  public static int max(int a, int b)  {    return (a > b) ? a : b;  }   // Driver code  static public void Main (){     for(int i = 0; i < 1000; i++)    {      for(int j = 0; j < 1000; j++)      {        arr[i, j] = -1;      }    }    String X = "AGGTAB";    String Y = "GXTXAYB";     int m = X.Length;    int n = Y.Length;     Console.WriteLine("Length of LCS is " + lcs(X, Y, m, n));  }} // This code is contributed by Dharanendra L V.
<script>// Javascript program to memoize// recursive implementation of LCS problem         let arr=new Array(1000);    for(let i=0;i<1000;i++)    {        arr[i]=new Array(1000);        for(let j=0;j<1000;j++)        {            arr[i][j]=-1;        }    }         // Returns length of LCS for X[0..m-1], Y[0..n-1] */  // memoization applied in recursive solution    function lcs(X,Y,m,n)    {        // base case    if (m == 0 || n == 0)      return 0;      // if the same state has already been    // computed    if (arr[m - 1][n - 1] != -1)        return arr[m - 1][n - 1];      // if equal, then we store the value of the    // function call    if ( X[m-1] == Y[n-1])    {        // store it in arr to avoid further repetitive      // work in future function calls      arr[m - 1][n - 1] = 1 + lcs(X, Y, m - 1, n - 1);      return arr[m - 1][n - 1];    }    else    {        // store it in arr to avoid further repetitive      // work in future function calls      arr[m - 1][n - 1] = Math.max(lcs(X, Y, m, n - 1),                              lcs(X, Y, m - 1, n));      return arr[m - 1][n - 1];    }    }                   // Driver code    let X = "AGGTAB";    let Y = "GXTXAYB";    let m = X.length;    let n = Y.length;    document.write("Length of LCS is " + lcs(X, Y, m, n));           // This code is contributed by rag2127</script>
Length of LCS is 4
 
3-D Memoization
In the above program, the recursive function had only two arguments whose values were not constant after every function call. Below, an implementation where the recursive program has three non-constant arguments is done. For e.g., Program to solve the standard Dynamic Problem LCS problem for three strings. The general recursive solution of the problem is to generate all subsequences of both given sequences and find the longest matching subsequence. The total possible combinations will be 3n. Hence, a recursive solution will take O(3n). Given below is the recursive solution to the LCS problem:  
C++
Java
Python3
C#
Javascript
// A recursive implementation of LCS problem// of three strings#include <bits/stdc++.h>int max(int a, int b); // Returns length of LCS for X[0..m-1], Y[0..n-1]int lcs(char* X, char* Y, char* Z, int m, int n, int o){    // base case    if (m == 0 || n == 0 || o == 0)        return 0;     // if equal, then check for next combination    if (X[m - 1] == Y[n - 1] and Y[n - 1] == Z[o - 1]) {         // recursive call        return 1 + lcs(X, Y, Z, m - 1, n - 1, o - 1);    }    else {         // return the maximum of the three other        // possible states in recursion        return max(lcs(X, Y, Z, m, n - 1, o),                   max(lcs(X, Y, Z, m - 1, n, o),                       lcs(X, Y, Z, m, n, o - 1)));    }} // Utility function to get max of 2 integersint max(int a, int b){    return (a > b) ? a : b;} // Driver Codeint main(){     char X[] = "geeks";    char Y[] = "geeksfor";    char Z[] = "geeksforge";    int m = strlen(X);    int n = strlen(Y);    int o = strlen(Z);    printf("Length of LCS is %d", lcs(X, Y, Z, m, n, o));     return 0;}
// A recursive implementation of LCS problem// of three stringsclass GFG{  // Utility function to get max of 2 integers  static int max(int a, int b)  {    return (a > b) ? a : b;  }   // Returns length of LCS for X[0..m-1], Y[0..n-1]  static int lcs(char[] X, char[] Y, char[] Z,                 int m, int n, int o)  {     // base case    if (m == 0 || n == 0 || o == 0)      return 0;     // if equal, then check for next combination    if (X[m - 1] == Y[n - 1] && Y[n - 1] == Z[o - 1])    {       // recursive call      return 1 + lcs(X, Y, Z, m - 1, n - 1, o - 1);    }    else    {       // return the maximum of the three other      // possible states in recursion      return Math.max(lcs(X, Y, Z, m, n - 1, o),                      Math.max(lcs(X, Y, Z, m - 1, n, o),                               lcs(X, Y, Z, m, n, o - 1)));    }  }   // Driver code  public static void main(String[] args)  {    char[] X = "geeks".toCharArray();    char[] Y = "geeksfor".toCharArray();    char[] Z = "geeksforge".toCharArray();    int m = X.length;    int n = Y.length;    int o = Z.length;    System.out.println("Length of LCS is " + lcs(X, Y, Z, m, n, o));  }} // This code is contributed by divyesh072019.
# A recursive implementation of LCS problem of three strings # Returns length of LCS for X[0..m-1], Y[0..n-1]def lcs(X, Y, Z, m, n, o):    # base case    if m == 0 or n == 0 or o == 0:      return 5         # if equal, then check for next combination    if X[m - 1] == Y[n - 1] and Y[n - 1] == Z[o - 1]:      # recursive call      return 1 + lcs(X, Y, Z, m - 1, n - 1, o - 1)    else:      # return the maximum of the three other      # possible states in recursion      return max(lcs(X, Y, Z, m, n - 1, o), max(lcs(X, Y, Z, m - 1, n, o), lcs(X, Y, Z, m, n, o - 1))) X = "geeks".split()Y = "geeksfor".split()Z = "geeksforge".split()m = len(X)n = len(Y)o = len(Z)print("Length of LCS is", lcs(X, Y, Z, m, n, o)) # This code is contributed by rameshtravel07.
// A recursive implementation of LCS problem// of three stringsusing System;class GFG {         // Utility function to get max of 2 integers    static int max(int a, int b)    {        return (a > b) ? a : b;    }     // Returns length of LCS for X[0..m-1], Y[0..n-1]    static int lcs(char[] X, char[] Y, char[] Z, int m, int n, int o)    {               // base case        if (m == 0 || n == 0 || o == 0)            return 0;              // if equal, then check for next combination        if (X[m - 1] == Y[n - 1] && Y[n - 1] == Z[o - 1])        {                  // recursive call            return 1 + lcs(X, Y, Z, m - 1, n - 1, o - 1);        }        else        {                  // return the maximum of the three other            // possible states in recursion            return Math.Max(lcs(X, Y, Z, m, n - 1, o),                       Math.Max(lcs(X, Y, Z, m - 1, n, o),                           lcs(X, Y, Z, m, n, o - 1)));        }    }   // Driver code  static void Main()  {    char[] X = "geeks".ToCharArray();    char[] Y = "geeksfor".ToCharArray();    char[] Z = "geeksforge".ToCharArray();    int m = X.Length;    int n = Y.Length;    int o = Z.Length;    Console.WriteLine("Length of LCS is " + lcs(X, Y, Z, m, n, o));  }} // This code is contributed by divyeshrabadiya07
<script> // A recursive implementation of LCS problem// of three strings         // Returns length of LCS for X[0..m-1], Y[0..n-1]    function lcs(X,Y,Z,m,n,o)    {        // base case    if (m == 0 || n == 0 || o == 0)      return 0;      // if equal, then check for next combination    if (X[m - 1] == Y[n - 1] && Y[n - 1] == Z[o - 1])    {        // recursive call      return 1 + lcs(X, Y, Z, m - 1, n - 1, o - 1);    }    else    {        // return the maximum of the three other      // possible states in recursion      return Math.max(lcs(X, Y, Z, m, n - 1, o),                      Math.max(lcs(X, Y, Z, m - 1, n, o),                               lcs(X, Y, Z, m, n, o - 1)));    }    }         // Driver code    let X = "geeks".split("");    let Y = "geeksfor".split("");    let Z = "geeksforge".split("");    let m = X.length;    let n = Y.length;    let o = Z.length;    document.write(    "Length of LCS is " + lcs(X, Y, Z, m, n, o)    );      // This code is contributed by unknown2108 </script>
Length of LCS is 5
 
The tabulation method has been shown here. On drawing the recursion tree completely, it has been noticed that there are many overlapping sub-problems which are been calculated multiple times. Since the function parameter has three non-constant parameters, hence a 3-D array will be used to memorize the value that was returned when lcs(x, y, z, m, n, o) for any value of m, n, and o was called so that if lcs(x, y, z, m, n, o) is again called for the same value of m, n, and o then the function will return the already stored value as it has been computed previously in the recursive call. arr[m][n][o] stores the value returned by the lcs(x, y, z, m, n, o) function call. The only modification that needs to be done in the recursive program is to store the return value of (m, n, o) state of the recursive function. The rest remains the same in the above recursive program. Below is the implementation of the Memoization approach of the recursive code:  
C++
Java
Python3
C#
Javascript
// A memoize recursive implementation of LCS problem#include <bits/stdc++.h>int arr[100][100][100];int max(int a, int b); // Returns length of LCS for X[0..m-1], Y[0..n-1] */// memoization applied in recursive solutionint lcs(char* X, char* Y, char* Z, int m, int n, int o){    // base case    if (m == 0 || n == 0 || o == 0)        return 0;     // if the same state has already been    // computed    if (arr[m - 1][n - 1][o - 1] != -1)        return arr[m - 1][n - 1][o - 1];     // if equal, then we store the value of the    // function call    if (X[m - 1] == Y[n - 1] and Y[n - 1] == Z[o - 1]) {         // store it in arr to avoid further repetitive work        // in future function calls        arr[m - 1][n - 1][o - 1] = 1 + lcs(X, Y, Z, m - 1,                                            n - 1, o - 1);        return arr[m - 1][n - 1][o - 1];    }    else {         // store it in arr to avoid further repetitive work        // in future function calls        arr[m - 1][n - 1][o - 1] =                               max(lcs(X, Y, Z, m, n - 1, o),                                 max(lcs(X, Y, Z, m - 1, n, o),                                    lcs(X, Y, Z, m, n, o - 1)));        return arr[m - 1][n - 1][o - 1];    }} // Utility function to get max of 2 integersint max(int a, int b){    return (a > b) ? a : b;} // Driver Codeint main(){    memset(arr, -1, sizeof(arr));    char X[] = "geeks";    char Y[] = "geeksfor";    char Z[] = "geeksforgeeks";    int m = strlen(X);    int n = strlen(Y);    int o = strlen(Z);    printf("Length of LCS is %d", lcs(X, Y, Z, m, n, o));     return 0;}
// A memoize recursive implementation of LCS problemimport java.io.*;class GFG{     public static int[][][] arr = new int[100][100][100];   // Returns length of LCS for X[0..m-1], Y[0..n-1] */  // memoization applied in recursive solution  static int lcs(String X, String Y, String Z,                 int m, int n, int o)  {           // base case      if (m == 0 || n == 0 || o == 0)          return 0;       // if the same state has already been      // computed      if (arr[m - 1][n - 1][o - 1] != -1)          return arr[m - 1][n - 1][o - 1];       // if equal, then we store the value of the      // function call      if (X.charAt(m - 1) == Y.charAt(n - 1) &&          Y.charAt(n - 1) == Z.charAt(o - 1)) {           // store it in arr to avoid further repetitive work          // in future function calls          arr[m - 1][n - 1][o - 1] = 1 + lcs(X, Y, Z, m - 1,                                              n - 1, o - 1);          return arr[m - 1][n - 1][o - 1];      }      else      {           // store it in arr to avoid further repetitive work          // in future function calls          arr[m - 1][n - 1][o - 1] =                                 max(lcs(X, Y, Z, m, n - 1, o),                                   max(lcs(X, Y, Z, m - 1, n, o),                                      lcs(X, Y, Z, m, n, o - 1)));          return arr[m - 1][n - 1][o - 1];      }  }   // Utility function to get max of 2 integers  static int max(int a, int b)  {      return (a > b) ? a : b;  }   // Driver Code  public static void main (String[] args)  {     for(int i = 0; i < 100; i++)    {      for(int j = 0; j < 100; j++)      {        for(int k = 0; k < 100; k++)        {          arr[i][j][k] = -1;        }      }    }         String X = "geeks";    String Y = "geeksfor";    String Z = "geeksforgeeks";    int m = X.length();    int n = Y.length();    int o = Z.length();    System.out.print("Length of LCS is " + lcs(X, Y, Z, m, n, o));  }} // This code is contributed by Dharanendra L V.
# A memoize recursive implementation of LCS problem # Returns length of LCS for X[0..m-1], Y[0..n-1] */# memoization applied in recursive solutiondef lcs(X, Y, Z, m, n, o):    global arr     # base case    if(m == 0 or n == 0 or o == 0):        return 0     # if the same state has already been    # computed    if (arr[m - 1][n - 1][o - 1] != -1):        return arr[m - 1][n - 1][o - 1]     # if equal, then we store the value of the    # function call    if (X[m - 1] == Y[n - 1] and            Y[n - 1] == Z[o - 1]):         # store it in arr to avoid further repetitive work        # in future function calls        arr[m - 1][n - 1][o - 1] = 1 + lcs(X, Y, Z, m - 1,                                           n - 1, o - 1)        return arr[m - 1][n - 1][o - 1]     else:         # store it in arr to avoid further repetitive work        # in future function calls        arr[m - 1][n - 1][o - 1] = max(lcs(X, Y, Z, m, n - 1, o),                                       max(lcs(X, Y, Z, m - 1, n, o), lcs(X, Y, Z, m, n, o - 1)))        return arr[m - 1][n - 1][o - 1] # Driver Codearr = [[[0 for k in range(100)] for j in range(100)] for i in range(100)] for i in range(100):    for j in range(100):        for k in range(100):            arr[i][j][k] = -1 X = "geeks"Y = "geeksfor"Z = "geeksforgeeks"m = len(X)n = len(Y)o = len(Z)print("Length of LCS is ", lcs(X, Y, Z, m, n, o)) # This code is contributed by Dharanendra L V.
// A memoize recursive implementation of LCS problemusing System;public class GFG{   public static int[, , ] arr = new int[100, 100, 100];   // Returns length of LCS for X[0..m-1], Y[0..n-1] */  // memoization applied in recursive solution  static int lcs(String X, String Y, String Z, int m, int n, int o)  {      // base case      if (m == 0 || n == 0 || o == 0)          return 0;       // if the same state has already been      // computed      if (arr[m - 1, n - 1, o - 1] != -1)          return arr[m - 1, n - 1, o - 1];       // if equal, then we store the value of the      // function call      if (X[m - 1] == Y[n - 1] &&          Y[n - 1] == Z[o - 1]) {           // store it in arr to avoid further repetitive work          // in future function calls          arr[m - 1, n - 1, o - 1] = 1 + lcs(X, Y, Z, m - 1,                                              n - 1, o - 1);          return arr[m - 1, n - 1, o - 1];      }      else {           // store it in arr to avoid further repetitive work          // in future function calls          arr[m - 1, n - 1, o - 1] =                                 max(lcs(X, Y, Z, m, n - 1, o),                                   max(lcs(X, Y, Z, m - 1, n, o),                                      lcs(X, Y, Z, m, n, o - 1)));          return arr[m - 1, n - 1, o - 1];      }  }   // Utility function to get max of 2 integers  static int max(int a, int b)  {      return (a > b) ? a : b;  }   // Driver Code  static public void Main (){     for(int i = 0; i < 100; i++) {      for(int j = 0; j < 100; j++) {        for(int k = 0; k < 100; k++) {          arr[i, j, k] = -1;        }      }    }         String X = "geeks";    String Y = "geeksfor";    String Z = "geeksforgeeks";    int m = X.Length;    int n = Y.Length;    int o = Z.Length;    Console.WriteLine("Length of LCS is " + lcs(X, Y, Z, m, n, o));  }} // This code is contributed by Dharanendra L V.
<script>// A memoize recursive implementation of LCS problem         let arr=new Array(100);    for(let i=0;i<100;i++)    {        arr[i]=new Array(100);        for(let j=0;j<100;j++)        {            arr[i][j]=new Array(100);            for(let k=0;k<100;k++)            {                arr[i][j][k]=-1;            }        }    }         // Returns length of LCS for X[0..m-1], Y[0..n-1] */  // memoization applied in recursive solution    function lcs(X,Y,Z,m,n,o)    {        // base case      if (m == 0 || n == 0 || o == 0)          return 0;        // if the same state has already been      // computed      if (arr[m - 1][n - 1][o - 1] != -1)          return arr[m - 1][n - 1][o - 1];        // if equal, then we store the value of the      // function call      if (X[m-1] == Y[n-1] &&          Y[n-1] == Z[o-1]) {            // store it in arr to avoid further repetitive work          // in future function calls          arr[m - 1][n - 1][o - 1] = 1 + lcs(X, Y, Z, m - 1,                                              n - 1, o - 1);          return arr[m - 1][n - 1][o - 1];      }      else      {            // store it in arr to avoid further repetitive work          // in future function calls          arr[m - 1][n - 1][o - 1] =                                 max(lcs(X, Y, Z, m, n - 1, o),                                   max(lcs(X, Y, Z, m - 1, n, o),                                      lcs(X, Y, Z, m, n, o - 1)));          return arr[m - 1][n - 1][o - 1];      }    }         // Utility function to get max of 2 integers    function max(a,b)    {         return (a > b) ? a : b;    }         // Driver Code    let X = "geeks";    let Y = "geeksfor";    let Z = "geeksforgeeks";    let m = X.length;    let n = Y.length;    let o = Z.length;    document.write("Length of LCS is " + lcs(X, Y, Z, m, n, o));            // This code is contributed by patel2127</script>
Length of LCS is 5
 
Note: The array used to Memoize is initialized to some value (say -1) before the function call to mark if the function with the same parameters has been previously called or not. 
jit_t
Shivi_Aggarwal
ukasp
vvkbisht
rohitsingh07052
subhammahato348
divyeshrabadiya07
divyesh072019
rutvik_56
manupathria
dharanendralv23
mukesh07
avanitrachhadiya2155
rag2127
unknown2108
patel2127
akshaysingh98088
rameshtravel07
Fibonacci
LCS
Dynamic Programming
Recursion
Dynamic Programming
Recursion
Fibonacci
LCS
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Bellman–Ford Algorithm | DP-23
Floyd Warshall Algorithm | DP-16
Subset Sum Problem | DP-25
Coin Change | DP-7
Matrix Chain Multiplication | DP-8
Write a program to print all permutations of a given string
Given an array A[] and a number x, check for pair in A[] with sum as x (aka Two Sum)
Recursion
Program for Tower of Hanoi
Backtracking | Introduction