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 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.
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