Sunday, June 8, 2014

[LeetCode] Unique Binary Search Trees I && II

Unique Binary Search Trees I

Problem Statement (link):
Given n, how many structurally unique BST's (binary search trees) that store values 1...n?
For example,
Given n = 3, there are a total of 5 unique BST's.
   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3
Analysis:
At first sight, this problem seems complicated. We may get some salt if we divide the problem into smaller sub-problems.

If n=0, there is 1 BST, which is the NULL tree.
If n=1, there is 1 BST, which is the single root node.
If n=2, there is 2 BST, which are BST with 1 being the root and 2 being the root.
...

We observe that for a value k, the root node may be any k=[1:n]. Thus, the number of BSTs in total is the number of sub-trees with node k valued from 1 to n.

Suppose the root node is k, then its left sub-tree consists of all nodes less that k, it's right sub-tree consists of all nodes larger than k. Then number of BSTs with root node k is then the product of number of BSTs of left sub-tree and number of BSTs of right sub-tree. Further, The number of BSTs of the left sub-tree is the number of sub-trees with the left root node valued from 1 to k-1, the number of BSTs of the right sub-tree is the number of sub-sub-trees with the right root node valued from k+1 to n. Thus we could model and solve this problem with recursion.

Furthermore, if we think twice about the method, it's sort of similar to the idea of DP - having previous calculated results stored, calculate and update new results.

Code:
class Solution {
public:
    int numTrees(int n) {
        // count[i] - number of unique BST constructed from i nodes
        vector<int> count(n+1);
        count[0] = 1;
        recur(count, n);
        return count[n];
    }

    void recur(vector<int> &count, int n) {
        for (int i=1; i<=n; i++) {
            // k - all possible num of nodes of left subtree
            for (int k=0; k<i; k++) {
                count[i] += count[k]*count[i-k-1];
            }
        }
    }
};


Unique Binary Search Trees II

Problem Statement (link):
Given n, generate all structurally unique BST's (binary search trees) that store values 1...n.
For example,
Given n = 3, your program should return all 5 unique BST's shown below.
   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3
Analysis:
This problem is a bit difficult as it's not easy to come up with a clear solution.

First, the problem asks for "all" BSTs, similar to the previous problem, we consider using DFS on every possible node values, i.e., from 1 through n.

The difficulty lies in finding a way to store each BST. The root node's value i of a valid BST must be within 1 and n, the root of its left subtree must be within 1 and i-1, the root of its right subtree must be within i+1 and n. This idea is same as that of the previous problem. Now, suppose we have all the possible nodes stored in two vectors - leftSub and rightSub, in order to construct a tree, we must construct a new root node with value i that points to a member in leftSub and points to a member in rightSub, respectively. Then, we push the node into our result vector.

Codes:
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<TreeNode *> generateTrees(int n) {
        vector<TreeNode*> res;
        recur(1, n, res);
        return res;
    }
    void recur(int l, int r, vector<TreeNode*> &res) {
        if (l>r) 
            res.push_back(NULL);
        else {
            for (int i=l; i<=r; i++) {
                // recursively build-up left and right subtree for root node i
                vector<TreeNode*> leftSub, rightSub;
                recur(l, i-1, leftSub);
                recur(i+1, r, rightSub);
                // Choose left and right subtree combinations for root node i
                for (int j=0; j<leftSub.size(); j++) {
                    for (int k=0; k<rightSub.size(); k++) { 
                        TreeNode* node=new TreeNode(i);
                        node->left = leftSub[j];
                        node->right= rightSub[k];
                        res.push_back(node);
                    }
                }
            }
        }
    }
};


No comments:

Post a Comment