Most of the Dynamic Programming problems are solved in two ways:
- 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 code
- Memoize the return value and use it to reduce recursive calls.
1-D Memoization
The 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++
#include <bits/stdc++.h>
using namespace std;
int fib( int n)
{
if (n <= 1)
return n;
return fib(n - 1) + fib(n - 2);
}
int main()
{
int n = 6;
printf ( "%d" , fib(n));
return 0;
}
|
Java
import java.io.*;
class GFG
{
static int fib( int n)
{
if (n <= 1 )
return n;
return fib(n - 1 ) +
fib(n - 2 );
}
public static void main (String[] args)
{
int n = 6 ;
System.out.println(fib(n));
}
}
|
Python3
def fib(n):
if (n < = 1 ):
return n
return fib(n - 1 ) + fib(n - 2 )
if __name__ = = '__main__' :
n = 6
print (fib(n))
|
C#
using System;
class GFG
{
static int fib( int n)
{
if (n <= 1)
return n;
return fib(n - 1) +
fib(n - 2);
}
static public void Main ()
{
int n = 6;
Console.WriteLine(fib(n));
}
}
|
Javascript
<script>
function fib(n)
{
if (n <= 1)
return n;
return fib(n - 1) + fib(n - 2);
}
let n = 6;
document.write(fib(n));
</script>
|
PHP
<?php
function fib( $n )
{
if ( $n <= 1)
return $n ;
return fib( $n - 1) +
fib( $n - 2);
}
$n = 6;
echo fib( $n );
?>
|
Time Complexity: O(2^n)
As at every stage we need to take 2 function calls and the height of the tree will be of the order of n.
Auxiliary Space: O(n)
The extra space is used due to recursion call stack.
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 than 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++
#include <bits/stdc++.h>
using namespace std;
int term[1000];
int fib( int n)
{
if (n <= 1)
return n;
if (term[n] != 0)
return term[n];
else {
term[n] = fib(n - 1) + fib(n - 2);
return term[n];
}
}
int main()
{
int n = 6;
printf ( "%d" , fib(n));
return 0;
}
|
Java
import java.io.*;
class GFG
{
static int []term = new int [ 1000 ];
static int fib( int n)
{
if (n <= 1 )
return n;
if (term[n] != 0 )
return term[n];
else
{
term[n] = fib(n - 1 ) +
fib(n - 2 );
return term[n];
}
}
public static void main (String[] args)
{
int n = 6 ;
System.out.println(fib(n));
}
}
|
Python3
term = [ 0 for i in range ( 1000 )]
def fib(n):
if n < = 1 :
return n
if term[n] ! = 0 :
return term[n]
else :
term[n] = fib(n - 1 ) + fib(n - 2 )
return term[n]
n = 6
print (fib(n))
|
C#
using System;
class GFG
{
static int fib( int n)
{
int [] term = new int [1000];
if (n <= 1)
return n;
if (term[n] != 0)
return term[n];
else
{
term[n] = fib(n - 1) +
fib(n - 2);
return term[n];
}
}
public static void Main ()
{
int n = 6;
Console.Write(fib(n));
}
}
|
Javascript
<script>
function fib(n)
{
let term = new Array(1000);
term.fill(0);
if (n <= 1)
return n;
if (term[n] != 0)
return term[n];
else
{
term[n] = fib(n - 1) +
fib(n - 2);
return term[n];
}
}
let n = 6;
document.write(fib(n));
</script>
|
Time Complexity: O(n)
As we have to calculate values for all function calls just once and there will be n values of arguments so the complexity will reduce to O(n).
Auxiliary Space: O(n)
The extra space is used due to recursion call stack.
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 Memoization
In 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++
#include <bits/stdc++.h>
int max( int a, int b);
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));
}
int max( int a, int b)
{
return (a > b) ? a : b;
}
int 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;
}
|
Java
import java.io.*;
class GFG
{
static int max( int a, int b) { return (a > b) ? a : b; }
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));
}
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));
}
}
|
Python3
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));
if __name__ = = '__main__' :
X = "AGGTAB" ;
Y = "GXTXAYB" ;
m = len (X);
n = len (Y);
print ( "Length of LCS is {}n" . format (lcs(X, Y, m, n)))
|
C#
using System;
class GFG
{
static int max( int a, int b) { return (a > b) ? a : b; }
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));
}
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));
}
}
|
Javascript
<script>
function max(a,b)
{
return (a > b) ? a : b;
}
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));
}
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));
</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++
#include <bits/stdc++.h>
int arr[1000][1000];
int max( int a, int b);
int lcs( char * X, char * Y, int m, int n)
{
if (m == 0 || n == 0)
return 0;
if (arr[m - 1][n - 1] != -1)
return arr[m - 1][n - 1];
if (X[m - 1] == Y[n - 1]) {
arr[m - 1][n - 1] = 1 + lcs(X, Y, m - 1, n - 1);
return arr[m - 1][n - 1];
}
else {
arr[m - 1][n - 1] = max(lcs(X, Y, m, n - 1),
lcs(X, Y, m - 1, n));
return arr[m - 1][n - 1];
}
}
int max( int a, int b)
{
return (a > b) ? a : b;
}
int 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
import java.io.*;
import java.lang.*;
class GFG
{
public static int arr[][] = new int [ 1000 ][ 1000 ];
public static int lcs(String X, String Y, int m, int n)
{
if (m == 0 || n == 0 )
return 0 ;
if (arr[m - 1 ][n - 1 ] != - 1 )
return arr[m - 1 ][n - 1 ];
if ( X.charAt(m - 1 ) == Y.charAt(n - 1 ))
{
arr[m - 1 ][n - 1 ] = 1 + lcs(X, Y, m - 1 , n - 1 );
return arr[m - 1 ][n - 1 ];
}
else
{
arr[m - 1 ][n - 1 ] = max(lcs(X, Y, m, n - 1 ),
lcs(X, Y, m - 1 , n));
return arr[m - 1 ][n - 1 ];
}
}
public static int max( int a, int b)
{
return (a > b) ? a : b;
}
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));
}
}
|
Python3
def lcs(X, Y, m, n):
global arr
if (m = = 0 or n = = 0 ):
return 0
if (arr[m - 1 ][n - 1 ] ! = - 1 ):
return arr[m - 1 ][n - 1 ]
if (X[m - 1 ] = = Y[n - 1 ]):
arr[m - 1 ][n - 1 ] = 1 + lcs(X, Y, m - 1 , n - 1 )
return arr[m - 1 ][n - 1 ]
else :
arr[m - 1 ][n - 1 ] = max (lcs(X, Y, m, n - 1 ),
lcs(X, Y, m - 1 , n))
return arr[m - 1 ][n - 1 ]
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))
|
C#
using System;
public class GFG
{
public static int [, ] arr = new int [1000, 1000];
public static int lcs(String X, String Y, int m, int n)
{
if (m == 0 || n == 0)
return 0;
if (arr[m - 1, n - 1] != -1)
return arr[m - 1, n - 1];
if ( X[m - 1] == Y[n - 1])
{
arr[m - 1, n - 1] = 1 + lcs(X, Y, m - 1, n - 1);
return arr[m - 1, n - 1];
}
else
{
arr[m - 1, n - 1] = max(lcs(X, Y, m, n - 1),
lcs(X, Y, m - 1, n));
return arr[m - 1, n - 1];
}
}
public static int max( int a, int b)
{
return (a > b) ? a : b;
}
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));
}
}
|
Javascript
<script>
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;
}
}
function lcs(X,Y,m,n)
{
if (m == 0 || n == 0)
return 0;
if (arr[m - 1][n - 1] != -1)
return arr[m - 1][n - 1];
if ( X[m-1] == Y[n-1])
{
arr[m - 1][n - 1] = 1 + lcs(X, Y, m - 1, n - 1);
return arr[m - 1][n - 1];
}
else
{
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];
}
}
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));
</script>
|
Output:
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++
#include <bits/stdc++.h>
int max( int a, int b);
int lcs( char * X, char * Y, char * Z, int m, int n, int o)
{
if (m == 0 || n == 0 || o == 0)
return 0;
if (X[m - 1] == Y[n - 1] and Y[n - 1] == Z[o - 1]) {
return 1 + lcs(X, Y, Z, m - 1, n - 1, o - 1);
}
else {
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)));
}
}
int max( int a, int b)
{
return (a > b) ? a : b;
}
int main()
{
char X[] = "neveropen" ;
char Y[] = "neveropenfor" ;
char Z[] = "neveropenforge" ;
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;
}
|
Java
class GFG
{
static int max( int a, int b)
{
return (a > b) ? a : b;
}
static int lcs( char [] X, char [] Y, char [] Z,
int m, int n, int o)
{
if (m == 0 || n == 0 || o == 0 )
return 0 ;
if (X[m - 1 ] == Y[n - 1 ] && Y[n - 1 ] == Z[o - 1 ])
{
return 1 + lcs(X, Y, Z, m - 1 , n - 1 , o - 1 );
}
else
{
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 )));
}
}
public static void main(String[] args)
{
char [] X = "neveropen" .toCharArray();
char [] Y = "neveropenfor" .toCharArray();
char [] Z = "neveropenforge" .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));
}
}
|
Python3
def lcs(X, Y, Z, m, n, o):
if m = = 0 or n = = 0 or o = = 0 :
return 5
if X[m - 1 ] = = Y[n - 1 ] and Y[n - 1 ] = = Z[o - 1 ]:
return 1 + lcs(X, Y, Z, m - 1 , n - 1 , o - 1 )
else :
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 = "neveropen" .split()
Y = "neveropenfor" .split()
Z = "neveropenforge" .split()
m = len (X)
n = len (Y)
o = len (Z)
print ( "Length of LCS is" , lcs(X, Y, Z, m, n, o))
|
C#
using System;
class GFG {
static int max( int a, int b)
{
return (a > b) ? a : b;
}
static int lcs( char [] X, char [] Y, char [] Z, int m, int n, int o)
{
if (m == 0 || n == 0 || o == 0)
return 0;
if (X[m - 1] == Y[n - 1] && Y[n - 1] == Z[o - 1])
{
return 1 + lcs(X, Y, Z, m - 1, n - 1, o - 1);
}
else
{
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)));
}
}
static void Main()
{
char [] X = "neveropen" .ToCharArray();
char [] Y = "neveropenfor" .ToCharArray();
char [] Z = "neveropenforge" .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));
}
}
|
Javascript
<script>
function lcs(X,Y,Z,m,n,o)
{
if (m == 0 || n == 0 || o == 0)
return 0;
if (X[m - 1] == Y[n - 1] && Y[n - 1] == Z[o - 1])
{
return 1 + lcs(X, Y, Z, m - 1, n - 1, o - 1);
}
else
{
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)));
}
}
let X = "neveropen" .split( "" );
let Y = "neveropenfor" .split( "" );
let Z = "neveropenforge" .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)
);
</script>
|
Output:
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++
#include <bits/stdc++.h>
int arr[100][100][100];
int max( int a, int b);
int lcs( char * X, char * Y, char * Z, int m, int n, int o)
{
if (m == 0 || n == 0 || o == 0)
return 0;
if (arr[m - 1][n - 1][o - 1] != -1)
return arr[m - 1][n - 1][o - 1];
if (X[m - 1] == Y[n - 1] and Y[n - 1] == Z[o - 1]) {
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 {
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];
}
}
int max( int a, int b)
{
return (a > b) ? a : b;
}
int main()
{
memset (arr, -1, sizeof (arr));
char X[] = "neveropen" ;
char Y[] = "neveropenfor" ;
char Z[] = "neveropen" ;
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;
}
|
Java
import java.io.*;
class GFG
{
public static int [][][] arr = new int [ 100 ][ 100 ][ 100 ];
static int lcs(String X, String Y, String Z,
int m, int n, int o)
{
if (m == 0 || n == 0 || o == 0 )
return 0 ;
if (arr[m - 1 ][n - 1 ][o - 1 ] != - 1 )
return arr[m - 1 ][n - 1 ][o - 1 ];
if (X.charAt(m - 1 ) == Y.charAt(n - 1 ) &&
Y.charAt(n - 1 ) == Z.charAt(o - 1 )) {
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
{
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 ];
}
}
static int max( int a, int b)
{
return (a > b) ? a : b;
}
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 = "neveropen" ;
String Y = "neveropenfor" ;
String Z = "neveropen" ;
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));
}
}
|
Python3
def lcs(X, Y, Z, m, n, o):
global arr
if (m = = 0 or n = = 0 or o = = 0 ):
return 0
if (arr[m - 1 ][n - 1 ][o - 1 ] ! = - 1 ):
return arr[m - 1 ][n - 1 ][o - 1 ]
if (X[m - 1 ] = = Y[n - 1 ] and
Y[n - 1 ] = = Z[o - 1 ]):
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 :
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 ]
arr = [[[ 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 = "neveropen"
Y = "neveropenfor"
Z = "neveropen"
m = len (X)
n = len (Y)
o = len (Z)
print ( "Length of LCS is " , lcs(X, Y, Z, m, n, o))
|
C#
using System;
public class GFG{
public static int [, , ] arr = new int [100, 100, 100];
static int lcs(String X, String Y, String Z, int m, int n, int o)
{
if (m == 0 || n == 0 || o == 0)
return 0;
if (arr[m - 1, n - 1, o - 1] != -1)
return arr[m - 1, n - 1, o - 1];
if (X[m - 1] == Y[n - 1] &&
Y[n - 1] == Z[o - 1]) {
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 {
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];
}
}
static int max( int a, int b)
{
return (a > b) ? a : b;
}
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 = "neveropen" ;
String Y = "neveropenfor" ;
String Z = "neveropen" ;
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));
}
}
|
Javascript
<script>
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;
}
}
}
function lcs(X,Y,Z,m,n,o)
{
if (m == 0 || n == 0 || o == 0)
return 0;
if (arr[m - 1][n - 1][o - 1] != -1)
return arr[m - 1][n - 1][o - 1];
if (X[m-1] == Y[n-1] &&
Y[n-1] == Z[o-1]) {
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
{
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];
}
}
function max(a,b)
{
return (a > b) ? a : b;
}
let X = "neveropen" ;
let Y = "neveropenfor" ;
let Z = "neveropen" ;
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));
</script>
|
Output:
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.
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!