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.
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 3Analysis:
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.
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 3Analysis:
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