Given two integers N and H, the task is to find the count of distinct Binary Search Trees consisting of N nodes where the maximum depth or height of the tree is equal to H.
Note: The height of BST with only the root node is 0.
Examples:
Input: N = 2, H = 1
Output: 2
Explanation: The two BST’s are :Input: N = 3, H = 2
Output: 4
Explanation: The four BST are :
Naive Approach: The problem can be solved using Recursion which can be memoized to obtain a Dynamic Programming solution based on the following idea:
The problem can be efficiently solved by finding the count of BST’s having maximum depth upto H (i.e., [0 – H]) instead of exactly H.
Let f(N, H) represent the count of BST’s consisting of ‘N’ nodes and having maximum depth upto ‘H’. Then the solution for the above problem: count of BST’s having maximum depth of exactly ‘H’ is equal to f(N, H) – f(N, H – 1).
Follow the illustration below for a better understanding.
Illustration:
Consider: N = 3, H = 2
The answer for this example is : count of BST’s of maximum depth upto 2 – count of BST’s of maximum depth upto 1.
- Count of BST’s of maximum depth upto 2 is 5, they are:
- Count of BST’s of maximum depth upto 1 is 1, it is :
- Hence the count of BST’s of maximum depth equal to ‘2’ is 4.
Follow the steps mentioned below to solve the problem.
- The count of BST with Node i as root Node is equal to product of count of BST’s of left subtree formed by nodes 1 to i-1 and right subtree formed by nodes i+1 to N.
- In order to find the count of BST of left subtree, we can recursively call the same function for depth H-1 and N=i – 1. To find the count of BST of right subtree, recursively call the function for depth H-1 and N=N-i.
- Loop over all values of i from [1, N] as root node and add the product of count of left and right subtree to the result.
Time Complexity: O(N * 2N)
Auxiliary Space: O(1)
Efficient Approach: The above approach can be optimized by using Dynamic Programming because the above problem has Overlapping subproblems and an Optimal substructure. The subproblems can be stored in dp[][] table memoization where dp[N][H] stores the count of BST of maximum depth up to H consisting of N nodes. Follow the steps below to solve the problem:
- Initialize a global multidimensional array dp[105][105] with all values as -1 that stores the result of each recursive call.
- Define a recursive function, say countOfBST(N, H) and perform the following steps.
- Case 1: If N = 0, return 1.
- Case 2: If H = 0, return true if N = 1.
- If the result of the state dp[N][H] is already computed, return this value dp[N][H].
- Iterate over the range [1, N] using the variable ‘i‘ as root and perform the following operations.
- Multiply the value of recursive functions countOfBST(i – 1, H – 1) and countOfBST(N – i, H – 1). The two functions calculate the count of BST for the left and the right subtree respectively.
- Add the term to the final answer which stores the total count of BSTs possible for all roots from [1, N].
- Print the value returned by the function countOfBST(N, H).
Below is the implementation of the above approach :
// C++ code to implement the approach #include <bits/stdc++.h> using namespace std;
// Declaring a dp-array int dp[105][105];
const int mod = 1000000007;
// Function to find the count of // BST upto height 'H' consisting // of 'N' nodes. int countOfBST( int N, int H)
{ // Base Case1 : If N == 0, return
// 1 as a valid BST has been formed
if (N == 0) {
return 1;
}
// Base Case2 : If H == 0, return true
// if N == 1
if (H == 0) {
return N == 1;
}
// If the current state has already
// been computed, then return it.
if (dp[N][H] != -1) {
return dp[N][H];
}
// Initialize answer to 0.
int ans = 0;
// Iterate over all numbers from
// [1, N], with 'i' as root.
for ( int i = 1; i <= N; ++i) {
// Call the recursive functions to
// find count of BST of left and right
// subtrees. Add the product of
// both terms to the answer.
ans += (countOfBST(i - 1, H - 1) * 1LL
* countOfBST(N - i, H - 1))
% mod;
// Take modulo 1000000007
ans %= mod;
}
// Return ans
return dp[N][H] = ans;
} // Utility function to find the count // of BST upto height 'H' consisting // of 'N' nodes. int UtilCountOfBST( int N, int H)
{ // Initialize dp-array with -1.
memset (dp, -1, sizeof dp);
// If height is 0, return true if
// only one node is present.
if (H == 0) {
return (N == 1);
}
// Function call.
return (countOfBST(N, H)
- countOfBST(N, H - 1)
+ mod)
% mod;
} // Driver code int main()
{ // Number of nodes
int N = 3;
// Height of tree
int H = 2;
cout << UtilCountOfBST(N, H) << endl;
return 0;
} |
// Java implementation of above approach import java.io.*;
import java.util.*;
class GFG {
// Declaring a dp-array
static int [][] dp = new int [ 105 ][ 105 ];
static int mod = 1000000007 ;
// Function to find the count of
// BST upto height 'H' consisting
// of 'N' nodes.
static int countOfBST( int N, int H)
{
// Base Case1 : If N == 0, return
// 1 as a valid BST has been formed
if (N == 0 ) {
return 1 ;
}
// Base Case2 : If H == 0, return true
// if N == 1
if (H == 0 ) {
if (N == 1 )
return 1 ;
return 0 ;
}
// If the current state has already
// been computed, then return it.
if (dp[N][H] != - 1 ) {
return dp[N][H];
}
// Initialize answer to 0.
int ans = 0 ;
// Iterate over all numbers from
// [1, N], with 'i' as root.
for ( int i = 1 ; i <= N; ++i) {
// Call the recursive functions to
// find count of BST of left and right
// subtrees. Add the product of
// both terms to the answer.
ans += (countOfBST(i - 1 , H - 1 )
* countOfBST(N - i, H - 1 ))
% mod;
// Take modulo 1000000007
ans %= mod;
}
// Return ans
dp[N][H] = ans;
return dp[N][H];
}
// Utility function to find the count
// of BST upto height 'H' consisting
// of 'N' nodes.
static int UtilCountOfBST( int N, int H)
{
// Initialize dp-array with -1.
for ( int i = 0 ; i < 105 ; i++)
for ( int j = 0 ; j < 105 ; j++)
dp[i][j] = - 1 ;
// If height is 0, return true if
// only one node is present.
if (H == 0 ) {
if (N == 1 )
return 1 ;
return 0 ;
}
// Function call.
return (countOfBST(N, H) - countOfBST(N, H - 1 )
+ mod)
% mod;
}
// Driver Code
public static void main(String[] args)
{
// Number of nodes
int N = 3 ;
// Height of tree
int H = 2 ;
System.out.print(UtilCountOfBST(N, H));
}
} // This code is contributed by code_hunt. |
# python3 code to implement the approach # Declaring a dp-array dp = [[ - 1 for _ in range ( 105 )] for _ in range ( 105 )]
mod = 1000000007
# Function to find the count of # BST upto height 'H' consisting # of 'N' nodes. def countOfBST(N, H):
# Base Case1 : If N == 0, return
# 1 as a valid BST has been formed
if (N = = 0 ):
return 1
# Base Case2 : If H == 0, return true
# if N == 1
if (H = = 0 ):
return N = = 1
# If the current state has already
# been computed, then return it.
if (dp[N][H] ! = - 1 ):
return dp[N][H]
# Initialize answer to 0.
ans = 0
# Iterate over all numbers from
# [1, N], with 'i' as root.
for i in range ( 1 , N + 1 ):
# Call the recursive functions to
# find count of BST of left and right
# subtrees. Add the product of
# both terms to the answer.
ans + = (countOfBST(i - 1 , H - 1 ) * countOfBST(N - i, H - 1 )) % mod
# Take modulo 1000000007
ans % = mod
# Return ans
dp[N][H] = ans
return dp[N][H]
# Utility function to find the count # of BST upto height 'H' consisting # of 'N' nodes. def UtilCountOfBST(N, H):
# Initialize dp-array with -1.
# If height is 0, return true if
# only one node is present.
if (H = = 0 ):
return (N = = 1 )
# Function call.
return (countOfBST(N, H)
- countOfBST(N, H - 1 )
+ mod) % mod
# Driver code if __name__ = = "__main__" :
# Number of nodes
N = 3
# Height of tree
H = 2
print (UtilCountOfBST(N, H))
# This code is contributed by rakeshsahni
|
// C# code to implement the approach using System;
class GFG {
// Declaring a dp-array
static int [, ] dp = new int [105, 105];
const int mod = 1000000007;
// Function to find the count of
// BST upto height 'H' consisting
// of 'N' nodes.
static int countOfBST( int N, int H)
{
// Base Case1 : If N == 0, return
// 1 as a valid BST has been formed
if (N == 0) {
return 1;
}
// Base Case2 : If H == 0, return true
// if N == 1
if (H == 0) {
if (N == 1)
return 1;
return 0;
}
// If the current state has already
// been computed, then return it.
if (dp[N, H] != -1) {
return dp[N, H];
}
// Initialize answer to 0.
int ans = 0;
// Iterate over all numbers from
// [1, N], with 'i' as root.
for ( int i = 1; i <= N; ++i) {
// Call the recursive functions to
// find count of BST of left and right
// subtrees. Add the product of
// both terms to the answer.
ans += (countOfBST(i - 1, H - 1)
* countOfBST(N - i, H - 1))
% mod;
// Take modulo 1000000007
ans %= mod;
}
// Return ans
dp[N, H] = ans;
return dp[N, H];
}
// Utility function to find the count
// of BST upto height 'H' consisting
// of 'N' nodes.
static int UtilCountOfBST( int N, int H)
{
// Initialize dp-array with -1.
for ( int i = 0; i < 105; i++)
for ( int j = 0; j < 105; j++)
dp[i, j] = -1;
// If height is 0, return true if
// only one node is present.
if (H == 0) {
if (N == 1)
return 1;
return 0;
}
// Function call.
return (countOfBST(N, H) - countOfBST(N, H - 1)
+ mod)
% mod;
}
// Driver code
public static void Main()
{
// Number of nodes
int N = 3;
// Height of tree
int H = 2;
Console.Write(UtilCountOfBST(N, H));
}
} // This code is contributed by ukasp. |
<script> // JavaScript code for the above approach
// Declaring a dp-array
let dp = new Array(105);
for (let i = 0; i < dp.length; i++) {
dp[i] = new Array(105).fill(-1);
}
let mod = 1000000007;
// Function to find the count of
// BST upto height 'H' consisting
// of 'N' nodes.
function countOfBST(N, H) {
// Base Case1 : If N == 0, return
// 1 as a valid BST has been formed
if (N == 0) {
return 1;
}
// Base Case2 : If H == 0, return true
// if N == 1
if (H == 0) {
return N == 1;
}
// If the current state has already
// been computed, then return it.
if (dp[N][H] != -1) {
return dp[N][H];
}
// Initialize answer to 0.
let ans = 0;
// Iterate over all numbers from
// [1, N], with 'i' as root.
for (let i = 1; i <= N; ++i) {
// Call the recursive functions to
// find count of BST of left and right
// subtrees. Add the product of
// both terms to the answer.
ans += (countOfBST(i - 1, H - 1) * 1
* countOfBST(N - i, H - 1))
% mod;
// Take modulo 1000000007
ans %= mod;
}
// Return ans
return dp[N][H] = ans;
}
// Utility function to find the count
// of BST upto height 'H' consisting
// of 'N' nodes.
function UtilCountOfBST(N, H) {
// If height is 0, return true if
// only one node is present.
if (H == 0) {
return (N == 1);
}
// Function call.
return (countOfBST(N, H)
- countOfBST(N, H - 1)
+ mod)
% mod;
}
// Driver code
// Number of nodes
let N = 3;
// Height of tree
let H = 2;
document.write(UtilCountOfBST(N, H) + '<br>' );
// This code is contributed by Potta Lokesh </script>
|
4
Time Complexity: O(N2 * H)
Auxiliary Space: O(N * H)
Efficient approach : Using DP Tabulation method ( Iterative approach )
The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memorization(top-down) because memorization method needs extra stack space of recursion calls.
Steps to solve this problem :
- Create a table to store the solution of the subproblems.
- Initialize the table with base cases
- Fill up the table iteratively
- Return the final solution
Implementation :
// C++ program for the above approach #include <bits/stdc++.h> using namespace std;
const int mod = 1000000007;
// Function to find the count of // BST upto height 'H' consisting // of 'N' nodes. int countOfBST( int N, int H)
{ // Initialize dp-array
int dp[N + 1][H + 1];
memset (dp, 0, sizeof (dp));
// Base Case1 : If N == 0, return
// 1 as a valid BST has been formed
for ( int i = 0; i <= H; ++i) {
dp[0][i] = 1;
}
// Base Case2 : If H == 0, return true
// if N == 1
for ( int i = 1; i <= N; ++i) {
dp[i][0] = (i == 1);
}
// Iterate over all nodes and height
for ( int i = 1; i <= N; ++i) {
for ( int j = 1; j <= H; ++j) {
for ( int k = 1; k <= i; ++k) {
dp[i][j] = (dp[i][j] +
(dp[k - 1][j - 1] * 1LL * dp[i - k][j - 1]) % mod) %
mod;
}
}
}
// Return ans
return dp[N][H];
} // Utility function to find the count // of BST upto height 'H' consisting // of 'N' nodes. int UtilCountOfBST( int N, int H)
{ if (H == 0) {
return (N == 1);
}
// Function call.
return ((countOfBST(N, H) - countOfBST(N, H - 1) + mod) % mod);
} // Driver code int main()
{ // Number of nodes
int N = 3;
// Height of tree
int H = 2;
cout << UtilCountOfBST(N, H) << endl;
return 0;
} // this code is contributed by bhardwajji |
// Java program for the above approach public class CountOfBST {
static final int MOD = 1000000007 ;
// Function to find the count of // BST upto height 'H' consisting // of 'N' nodes. public static int countOfBST( int N, int H) {
// Initialize dp-array
int [][] dp = new int [N + 1 ][H + 1 ];
// Base Case1 : If N == 0, return
// 1 as a valid BST has been formed
for ( int i = 0 ; i <= H; i++) {
dp[ 0 ][i] = 1 ;
}
// Base Case2 : If H == 0, return true
// if N == 1
for ( int i = 1 ; i <= N; i++) {
dp[i][ 0 ] = (i == 1 ) ? 1 : 0 ;
}
// Iterate over all nodes and height
for ( int i = 1 ; i <= N; i++) {
for ( int j = 1 ; j <= H; j++) {
for ( int k = 1 ; k <= i; k++) {
dp[i][j] = (dp[i][j] + (dp[k - 1 ][j - 1 ] * dp[i - k][j - 1 ]) % MOD) % MOD;
}
}
}
// Return answer
return dp[N][H];
} // Utility function to find the count // of BST upto height 'H' consisting // of 'N' nodes. public static int UtilCountOfBST( int N, int H) {
if (H == 0 ) {
return (N == 1 ) ? 1 : 0 ;
}
// Function call
return ((countOfBST(N, H) - countOfBST(N, H - 1 ) + MOD) % MOD);
} // Driver code public static void main(String[] args) {
// Number of nodes
int N = 3 ;
// Height of tree
int H = 2 ;
// Printing the result
System.out.println(UtilCountOfBST(N, H));
}
} |
# Python program for the above approach MOD = 1000000007
# Function to find the count of # BST upto height 'H' consisting # of 'N' nodes. def countOfBST(N: int , H: int ) - > int :
# Initialize dp-array
dp = [[ 0 for j in range (H + 1 )] for i in range (N + 1 )]
# Base Case1 : If N == 0, return
# 1 as a valid BST has been formed
for i in range (H + 1 ):
dp[ 0 ][i] = 1
# Base Case2 : If H == 0, return true
# if N == 1
for i in range ( 1 , N + 1 ):
dp[i][ 0 ] = 1 if i = = 1 else 0
# Iterate over all nodes and height
for i in range ( 1 , N + 1 ):
for j in range ( 1 , H + 1 ):
for k in range ( 1 , i + 1 ):
dp[i][j] = (dp[i][j] +
(dp[k - 1 ][j - 1 ] * dp[i - k][j - 1 ]) % MOD) % MOD
# Return ans
return dp[N][H]
# Utility function to find the count # of BST upto height 'H' consisting # of 'N' nodes. def UtilCountOfBST(N: int , H: int ) - > int :
if H = = 0 :
return 1 if N = = 1 else 0
# Function call.
return ((countOfBST(N, H) - countOfBST(N, H - 1 ) + MOD) % MOD)
# Driver code if __name__ = = "__main__" :
# Number of nodes
N = 3
# Height of tree
H = 2
print (UtilCountOfBST(N, H))
|
using System;
public class CountOfBST {
const int MOD = 1000000007;
// Function to find the count of
// BST upto height 'H' consisting
// of 'N' nodes.
public static int Count( int N, int H) {
// Initialize dp-array
int [,] dp = new int [N+1, H+1];
// Base Case1 : If N == 0, return
// 1 as a valid BST has been formed
for ( int i = 0; i <= H; i++) {
dp[0, i] = 1;
}
// Base Case2 : If H == 0, return true
// if N == 1
for ( int i = 1; i <= N; i++) {
dp[i, 0] = (i == 1) ? 1 : 0;
}
// Iterate over all nodes and height
for ( int i = 1; i <= N; i++) {
for ( int j = 1; j <= H; j++) {
for ( int k = 1; k <= i; k++) {
dp[i, j] = (dp[i, j] +
(dp[k - 1, j - 1] * dp[i - k, j - 1]) % MOD) % MOD;
}
}
}
// Return ans
return dp[N, H];
}
// Utility function to find the count
// of BST upto height 'H' consisting
// of 'N' nodes.
public static int UtilCount( int N, int H) {
if (H == 0) {
return (N == 1) ? 1 : 0;
}
// Function call.
return ((Count(N, H) - Count(N, H - 1) + MOD) % MOD);
}
// Driver code
public static void Main() {
// Number of nodes
int N = 3;
// Height of tree
int H = 2;
Console.WriteLine(UtilCount(N, H));
}
} |
const MOD = 1000000007; /** * Function to find the count of BST upto height 'H'
* consisting of 'N' nodes.
*
* @param {number} N - The number of nodes.
* @param {number} H - The height of the tree.
* @returns {number} The count of BST.
*/
function countOfBST(N, H) {
// Initialize dp-array
const dp = Array.from({ length: N + 1 }, () =>
Array.from({ length: H + 1 }, () => 0)
);
// Base Case1 : If N == 0, return
// 1 as a valid BST has been formed
for (let i = 0; i <= H; i++) {
dp[0][i] = 1;
}
// Base Case2 : If H == 0, return true
// if N == 1
for (let i = 1; i <= N; i++) {
dp[i][0] = i === 1 ? 1 : 0;
}
// Iterate over all nodes and height
for (let i = 1; i <= N; i++) {
for (let j = 1; j <= H; j++) {
for (let k = 1; k <= i; k++) {
dp[i][j] = ((dp[i][j] +
((dp[k - 1][j - 1] * dp[i - k][j - 1]) % MOD)) %
MOD);
}
}
}
// Return ans
return dp[N][H];
} /** * Utility function to find the count of BST upto height 'H'
* consisting of 'N' nodes.
*
* @param {number} N - The number of nodes.
* @param {number} H - The height of the tree.
* @returns {number} The count of BST.
*/
function UtilCountOfBST(N, H) {
if (H === 0) {
return N === 1 ? 1 : 0;
}
// Function call.
return ((countOfBST(N, H) - countOfBST(N, H - 1) + MOD) % MOD);
} // Driver code if (require.main === module) {
// Number of nodes
const N = 3;
// Height of tree
const H = 2;
console.log(UtilCountOfBST(N, H));
} |
4
Time Complexity: O(N2 * H)
Auxiliary Space: O(N * H)