A BST is generated (by successive insertion of nodes) from each permutation of keys from the set
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}.
How many permutations determine trees of height three?
A BST is generated (by successive insertion of nodes) from each permutation of keys from the set
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}.
How many permutations determine trees of height three?
The number of permutations of nodes you have to check is 11! = 39,916,800, so you could just write a program to brute-force this. Here's a skeleton of one, written in C++:
vector<int> values = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
unsigned numSuccesses = 0;
do {
if (bstHeightOf(values) == 3) values++;
} while (next_permutation(values.begin(), values.end());
Here, you just need to write the bstHeightOf
function, which computes the height of a BST formed by inserting the given nodes in the specified order. I'll leave this as an exercise.
You can prune down the search space a bunch by using these observations:
Given that you know the possible roots, one option would be to generate all BSTs with the keys {1, 2, 3, ..., 11} (not by listing off all orderings, but by listing off all trees), filter it down just to the set of nodes with height 3, and then use this recursive algorithm to count the number of ways each tree can be built by inserting values. This would probably be significantly faster than the above approach, since the number of trees to check is much lower than the number of orderings and each tree can be checked in linear time.
Hope this helps!
An alternative to templatetypdef's answer that might be more tricky but can be done completely by hand.
Consider the complete binary tree of height 3: it has 15 nodes. You're looking for trees with 11 nodes; that means that four of those 15 nodes are missing. The patterns in which these missing nodes can occur can be enumerated with fairly little effort. (Hint: I did this by dividing the patterns into two groups.) This will give you all the shapes of trees of height 3 with 11 nodes.
Once you've done this, you just need to reason about the relationship between these tree shapes and the actual trees you're looking for. (Hint: this relationship is extremely simple - don't overthink it.)
This allows you to enumerate the resulting trees that satisfy the requirements. If you get to 96, you have the same result as I do. For each of these trees, we now need to find how many permutations give rise to that tree.
This part is the tricky part; you might now need to split these trees up into smaller groups for which you know, by symmetry, that the number of permutations that gives rise to that tree is the same for all trees in a group. For example,
6
/ \
/ \
3 8
/ \ / \
2 5 7 10
/ / / \
1 4 9 11
is going to have the same number of permutations that give rise to it as
6
/ \
/ \
4 9
/ \ / \
2 5 7 11
/ \ \ /
1 3 8 10
You'll also need to find out how many trees occur in each group; the class of this example contains 16 trees. (Hint: I split them up into 7 groups of between 2 and 32 trees.) Now you'll need to find the number of permutations that give rise to such a tree, for each group. You can determine this "recursively", still on paper; for the class containing the two example trees above, I get 12096 permutations. Since that class contains 16 trees, the total number of permutations leading to such a tree is 16*12069 = 193536. Do the same for the six other classes and add the numbers up to get the total.
If any particular part of this solution has you stumped or anything is unclear, don't hesitate to ask!
Since this site is about programming, I'll provide code to determine this. We can use a backtracking algorithm, that backtracks as soon as the height constraint is violated.
We can implement the BST as a flat array, where the children of a node at index k
are stored at indices 2*k
and 2*k + 1
. The root is at index 1. Index 0 is not used. When an index is not occupied we can store a special value there, like -1.
The algorithm is quite brute force, and on my laptop it takes about a 1.5 seconds to complete:
function insert(tree, value) {
let k = 1;
while (k < tree.length) {
if (tree[k] == -1) {
tree[k] = value;
return k;
}
k = 2*k + (value > tree[k] ? 1 : 0);
}
return -1;
}
function populate(tree, values) {
if (values.length == 0) return 1; // All values were inserted! Count this permutation
let count = 0;
for (let i = 0; i < values.length; i++) {
let value = values[i]
let node = insert(tree, value);
if (node >= 0) { // Height is OK
values.splice(i, 1); // Remove this value from remaining values
count += populate(tree, values);
values.splice(i, 0, value); // Backtrack
tree[node] = -1; // Free the node
}
}
return count;
}
function countTrees(n) {
// Create an empty tree as flat array of height 3,
// and provide n unique values to insert
return populate(Array(16).fill(-1), [...Array(n).keys()]);
}
console.log(countTrees(11));
Output: 1056000