[Naive Approach] Recursion - O(3 ^ n) Time and O(n) Space
The idea is to use Recursion, where we try every node as the root and recursively count the possible BSTs for its left and right subtrees.
For each root, multiply the number of BSTs possible in the left and right subtrees.
Add these products for all possible roots to get the total number of unique BSTs.
Why Does this Approach Work?
To understand the approach, let us write n numbers as an array [1, 2, .... n]. Let the count of all possible BSTs with n nodes be count(n). For each value i in the above array, we put [1, 2, ... i-1] into left subtree, make i as root and put [i+1, i+2, ... n] in right subtree. Hence count(n) can be written as summation of (count(i-1)*count(n-i)) where i lies in the range [1, n].
C++
#include<iostream>usingnamespacestd;// Function to return the total number of possible unique BSTs.intnumTrees(intn){// Base caseif(n<=1)return1;intans=0;// Try every node as the root.for(introot=1;root<=n;root++){// Count BSTs formed by the left and right subtrees.ans+=numTrees(root-1)*numTrees(n-root);}// Return the total number of unique BSTs.returnans;}intmain(){intn=3;cout<<numTrees(n);return0;}
Java
publicclassGFG{// Function to return the total number of possible// unique BSTs.staticintnumTrees(intn){// Base caseif(n<=1)return1;intans=0;// Try every node as the root.for(introot=1;root<=n;root++){// Count BSTs formed by the left and right// subtrees.ans+=numTrees(root-1)*numTrees(n-root);}// Return the total number of unique BSTs.returnans;}publicstaticvoidmain(String[]args){intn=3;System.out.print(numTrees(n));}}
Python
# Function to return the total number of possible unique BSTs.defnumTrees(n):# Base caseifn<=1:return1ans=0# Try every node as the root.forrootinrange(1,n+1):# Count BSTs formed by the left and right subtrees.ans+=numTrees(root-1)*numTrees(n-root)# Return the total number of unique BSTs.returnansif__name__=='__main__':n=3print(numTrees(n))
C#
usingSystem;classGFG{// Function to return the total number of possible// unique BSTs.staticintnumTrees(intn){// Base caseif(n<=1)return1;intans=0;// Try every node as the root.for(introot=1;root<=n;root++){// Count BSTs formed by the left and right// subtrees.ans+=numTrees(root-1)*numTrees(n-root);}// Return the total number of unique BSTs.returnans;}staticvoidMain(){intn=3;Console.Write(numTrees(n));}}
JavaScript
// Function to return the total number of possible unique// BSTs.functionnumTrees(n){// Base caseif(n<=1)return1;letans=0;// Try every node as the root.for(letroot=1;root<=n;root++){// Count BSTs formed by the left and right subtrees.ans+=numTrees(root-1)*numTrees(n-root);}// Return the total number of unique BSTs.returnans;}// Driver Codeletn=3;console.log(numTrees(n));
Output
5
[Expected Approach] Dynamic Programming (Tabulation) - O(n ^ 2) Time and O(n) Space
The idea is to use Dynamic Programming (Tabulation), where dp[i] stores the number of unique BSTs that can be formed using i nodes.
For each possible root, multiply the number of BSTs possible in the left and right subtrees and add it to dp[i].
Fill the dp array from 0 to n and return dp[n].
Working of Approach:
Create a dp array where dp[i] stores the number of unique BSTs that can be formed using i nodes.
Initialize the base cases: dp[0] = 1 and dp[1] = 1, as there is exactly one BST with 0 or 1 node.
For each number of nodes from 2 to n, try every node as the root, multiply the number of possible left and right subtrees, and add the result to dp[i].
After filling the dp array, return dp[n], which represents the total number of structurally unique BSTs that can be formed using n nodes.
Let us understand with an example: Input: n = 3
Initialize dp[0] = 1 and dp[1] = 1, representing the number of unique BSTs with 0 and 1 node.
For i = 2, choose each node as the root: dp[2] = dp[0] × dp[1] + dp[1] × dp[0] = 1 + 1 = 2.
Store each computed value in the dp array and use it for subsequent calculations.
Finally, return dp[3] = 5, which is the total number of structurally unique BSTs that can be formed using 3 nodes.
C++
#include<iostream>#include<vector>usingnamespacestd;// Function to return the total number of possible unique BSTs.intnumTrees(intn){// dp[i] stores the number of unique BSTs// that can be formed using i nodes.intdp[n+1];// Base cases.dp[0]=1;dp[1]=1;// Fill the dp[] array in a bottom-up manner.for(inti=2;i<=n;i++){dp[i]=0;// Try every node as the root.for(intj=1;j<=i;j++){// If j is chosen as the root, then// nodes [1...j-1] form the left subtree and// nodes [j+1...i] form the right subtree.// Multiply the number of possible left and// right subtrees and add it to dp[i].dp[i]+=dp[j-1]*dp[i-j];}}// Return the total number of unique BSTs.returndp[n];}intmain(){intn=3;cout<<numTrees(n);return0;}
Java
publicclassGFG{// Function to return the total number of possible// unique BSTs.staticintnumTrees(intn){// dp[i] stores the number of unique BSTs// that can be formed using i nodes.int[]dp=newint[n+1];// Base cases.dp[0]=1;dp[1]=1;// Fill the dp[] array in a bottom-up manner.for(inti=2;i<=n;i++){dp[i]=0;// Try every node as the root.for(intj=1;j<=i;j++){// If j is chosen as the root, then// nodes [1...j-1] form the left subtree and// nodes [j+1...i] form the right subtree.// Multiply the number of possible left and// right subtrees and add it to dp[i].dp[i]+=dp[j-1]*dp[i-j];}}// Return the total number of unique BSTs.returndp[n];}publicstaticvoidmain(String[]args){intn=3;System.out.print(numTrees(n));}}
Python
# Function to return the total number of possible unique BSTs.defnumTrees(n):# dp[i] stores the number of unique BSTs# that can be formed using i nodes.dp=[0]*(n+1)# Base cases.dp[0]=1dp[1]=1# Fill the dp[] array in a bottom-up manner.foriinrange(2,n+1):dp[i]=0# Try every node as the root.forjinrange(1,i+1):# If j is chosen as the root, then# nodes [1...j-1] form the left subtree and# nodes [j+1...i] form the right subtree.# Multiply the number of possible left and# right subtrees and add it to dp[i].dp[i]+=dp[j-1]*dp[i-j]# Return the total number of unique BSTs.returndp[n]if__name__=='__main__':n=3print(numTrees(n))
C#
usingSystem;classGFG{// Function to return the total number of possible// unique BSTs.staticintnumTrees(intn){// dp[i] stores the number of unique BSTs// that can be formed using i nodes.int[]dp=newint[n+1];// Base cases.dp[0]=1;dp[1]=1;// Fill the dp[] array in a bottom-up manner.for(inti=2;i<=n;i++){dp[i]=0;// Try every node as the root.for(intj=1;j<=i;j++){// If j is chosen as the root, then// nodes [1...j-1] form the left subtree and// nodes [j+1...i] form the right subtree.// Multiply the number of possible left and// right subtrees and add it to dp[i].dp[i]+=dp[j-1]*dp[i-j];}}// Return the total number of unique BSTs.returndp[n];}staticvoidMain(){intn=3;Console.Write(numTrees(n));}}
JavaScript
// Function to return the total number of possible unique// BSTs.functionnumTrees(n){// dp[i] stores the number of unique BSTs// that can be formed using i nodes.letdp=newArray(n+1).fill(0);// Base cases.dp[0]=1;dp[1]=1;// Fill the dp[] array in a bottom-up manner.for(leti=2;i<=n;i++){dp[i]=0;// Try every node as the root.for(letj=1;j<=i;j++){// If j is chosen as the root, then// nodes [1...j-1] form the left subtree and// nodes [j+1...i] form the right subtree.// Multiply the number of possible left and// right subtrees and add it to dp[i].dp[i]+=dp[j-1]*dp[i-j];}}// Return the total number of unique BSTs.returndp[n];}letn=3;console.log(numTrees(n));