Open In App

Construct all possible BSTs for keys 1 to N

Last Updated : 29 Sep, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

Given an integer n, the task is to generate all possible Binary Search Trees (BSTs) that can be constructed using keys from 1 to n and print their preorder traversal.

Examples:

Input: n = 2
Output:
1 2
2 1

exampless-copy

Input: n = 3
Output:
1 2 3
1 3 2
2 1 3
3 1 2
3 2 1

example-1

How many structurally unique BSTs can be formed with keys from 1 to n?

  • The key observation is that for any i-th number chosen as the root, all numbers from 1 to i-1 must be in the left subtree (since they are smaller than the root), and all numbers from i+1 to n must be in the right subtree (since they are larger than the root).
  • If the numbers from 1 to i-1 can form x different trees and the numbers from i+1 to n can form y different trees, then for the i-th number as root, we can have x * y total unique BSTs.
  • Since we can choose any number from 1 to n as the root, we iterate over each possible root (from 1 to n) and calculate the total number of unique BSTs by summing up the product of the number of left and right subtrees for each root.
  • Upon observation, the number of structurally unique BSTs for n keys is equivalent to the n-th Catalan number, which can be computed using known formulas or dynamic programming.

Approach:

The idea is to construct all possible BSTs by considering each number from 1 to n as the root and recursively constructing the left and right subtrees. For each root i, all numbers from 1 to i-1 will form the left subtree, and numbers from i+1 to n will form the right subtree. We recursively generate all possible BSTs for the left and right subtrees and then combine each left subtree with each right subtree for the current root.

Follow the steps below to solve the problem:

  • Initialize a array of BSTs as empty.
  • For every number i from 1 to n, do the following:
    • Create a new node with key i, let this node be 'node'.
    • Recursively construct a list of all possible left subtrees from numbers 1 to i-1.
    • Recursively construct a list of all possible right subtrees from numbers i+1 to n.
  • Iterate over all possible left subtrees:
    • For each current left subtree, iterate over all possible right subtrees.
    • Attach the current left and right subtrees to 'node'.
    • Add the node (with attached subtrees) to the list of BSTs.

Below is the implementation of the above approach: 

C++
// C++ program to find all binary trees
// from 1 to n

#include <bits/stdc++.h>
using namespace std;

class Node {
public:
    int data;
    Node* left;
    Node* right;

    Node(int x) {
        data = x;
        left = right = nullptr;
    }
};

// Function to construct all possible binary trees 
vector<Node*> getTrees(int start, int end) {
    vector<Node*> trees;

    // Base case: If start index is greater than end, 
  	// return empty tree (nullptr)
    if (start > end) {
        trees.push_back(nullptr);
        return trees;
    }

    // Iterate through all values in the array 
  	// and construct left and right subtrees
    for (int i = start; i <= end; ++i) {
        
        // Generate all left subtrees
        vector<Node*> leftTrees = getTrees(start, i - 1);

        // Generate all right subtrees
        vector<Node*> rightTrees = getTrees(i + 1, end);

        // Combine each left and right subtree with 
      	// the current root
        for (Node* left : leftTrees) {
            for (Node* right : rightTrees) {
                
                // Make i as root
                Node* root = new Node(i); 
                root->left = left;
                root->right = right;

                // Add the constructed tree to the list of trees
                trees.push_back(root);
            }
        }
    }
    return trees;
}

void preorder(Node* root) {
    if (root != nullptr) {
        cout << root->data << " ";
        preorder(root->left);
        preorder(root->right);
    }
}

int main() {
    vector<Node*> trees = getTrees(1, 3);

    for (int i = 0; i < trees.size(); ++i) {
        preorder(trees[i]);
        cout << "\n";
    }

    return 0;
}
Java
// Java program to find all binary
// trees from 1 to n

import java.util.ArrayList;
import java.util.List;

class Node {
    int data;
    Node left, right;

    Node(int data) {
        this.data = data;
        left = right = null;
    }
}

class GfG {

    // Function to construct all possible binary trees
    static List<Node> getTrees(int start, int end) {
        List<Node> trees = new ArrayList<>();

        // Base case: If start index is greater than end, 
      	// return empty tree (null)
        if (start > end) {
            trees.add(null);
            return trees;
        }

        // Iterate through all values in the array and 
      	// construct left and right subtrees
        for (int i = start; i <= end; i++) {

            // Generate all left subtrees
            List<Node> leftTrees = getTrees(start, i - 1);

            // Generate all right subtrees
            List<Node> rightTrees = getTrees(i + 1, end);

            // Combine each left and right
          	// subtree with the current root
            for (Node left : leftTrees) {
                for (Node right : rightTrees) {

                    // Make i as root
                    Node root = new Node(i);
                    root.left = left;
                    root.right = right;

                    // Add the constructed tree to the
                  	// list of trees
                    trees.add(root);
                }
            }
        }
        return trees;
    }

    static void preorder(Node root) {
        if (root != null) {
            System.out.print(root.data + " ");
            preorder(root.left);
            preorder(root.right);
        }
    }

    public static void main(String[] args) {
        List<Node> trees = getTrees(1, 3);

        for (Node tree : trees) {
            preorder(tree);
            System.out.println();
        }
    }
}
Python
# Python program to find all binary
# trees from 1 to n
class Node:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None

# Function to construct all possible
# binary trees 
def get_trees(start, end):
    trees = []

    # Base case: If start index is greater than end, 
    # return empty tree (None)
    if start > end:
        trees.append(None)
        return trees

    # Iterate through all values in the array and 
    # construct left and right subtrees
    for i in range(start, end + 1):
        
        # Generate all left subtrees
        left_trees = get_trees(start, i - 1)

        # Generate all right subtrees
        right_trees = get_trees(i + 1, end)

        # Combine each left and right subtree 
        # with the current root
        for left in left_trees:
            for right in right_trees:
                
                # Make i as root
                root = Node(i)
                root.left = left
                root.right = right

                # Add the constructed tree to 
                # the list of trees
                trees.append(root)

    return trees

def preorder(root):
    if root is not None:
        print(root.data, end=" ")
        preorder(root.left)
        preorder(root.right)

if __name__ == "__main__":
    trees = get_trees(1, 3)

    for tree in trees:
        preorder(tree)
        print()
C#
// C# program to find all binary trees 
// from 1 to n

using System;
using System.Collections.Generic;

class Node {
    public int data;
    public Node left, right;

    public Node(int data) {
        this.data = data;
        this.left = this.right = null;
    }
}

class GfG {

    // Function to construct all possible binary trees 
    static List<Node> GetTrees(int start, int end) {
        List<Node> trees = new List<Node>();

        // Base case: If start index is greater than end, 
      	// return empty tree (null)
        if (start > end) {
            trees.Add(null);
            return trees;
        }

        // Iterate through all values in the array and 
      	// construct left and right subtrees
        for (int i = start; i <= end; i++) {

            // Generate all left subtrees
            List<Node> leftTrees = GetTrees(start, i - 1);

            // Generate all right subtrees
            List<Node> rightTrees = GetTrees(i + 1, end);

            // Combine each left and right subtree 
          	// with the current root
            foreach (Node left in leftTrees) {
                foreach (Node right in rightTrees) {

                    // Make i as root
                    Node root = new Node(i);
                    root.left = left;
                    root.right = right;

                    // Add the constructed tree to
                  	// the list of trees
                    trees.Add(root);
                }
            }
        }
        return trees;
    }

    static void Preorder(Node root) {
        if (root != null) {
            Console.Write(root.data + " ");
            Preorder(root.left);
            Preorder(root.right);
        }
    }

    static void Main(string[] args) {
        List<Node> trees = GetTrees(1, 3);

        foreach (Node tree in trees) {
            Preorder(tree);
            Console.WriteLine();
        }
    }
}
JavaScript
// JavaScript program to find all binary
// trees from 1 to n

class Node {
    constructor(data) {
        this.data = data;
        this.left = null;
        this.right = null;
    }
}

// Function to construct all possible binary trees
function getTrees(start, end) {
    const trees = [];

    // Base case: If start index is greater than end, 
    // return empty tree (null)
    if (start > end) {
        trees.push(null);
        return trees;
    }

    // Iterate through all values in the array 
    // and construct left and right subtrees
    for (let i = start; i <= end; i++) {

        // Generate all left subtrees
        const leftTrees = getTrees(start, i - 1);

        // Generate all right subtrees
        const rightTrees = getTrees(i + 1, end);

        // Combine each left and right subtree
        // with the current root
        leftTrees.forEach(left => {
            rightTrees.forEach(right => {

                // Make i as root
                const root = new Node(i);
                root.left = left;
                root.right = right;

                // Add the constructed tree to 
                // the list of trees
                trees.push(root);
            });
        });
    }

    return trees;
}

function preorder(root) {
    if (root !== null) {
        process.stdout.write(root.data + " ");
        preorder(root.left);
        preorder(root.right);
    }
}

const trees = getTrees(1, 3);

trees.forEach(tree => {
	preorder(tree);
	console.log();
});

Output
1 2 3 
1 3 2 
2 1 3 
3 1 2 
3 2 1 

Time Complexity: O(Cn​ * n), where Cn​ is the Catalan number
Auxiliary Space: O(Cn​ * n), for storing all possible trees and the space used by the recursion stack.

Related Articles


Next Article

Similar Reads