Given an integer n, return a list of all possible full binary trees with n nodes. Each node of each tree in the answer must have the value 0.
A full binary tree is a binary tree where every node has either 0 or 2 children. You may return the answer in any order.
n representing the number of nodes.n nodes, where each node has value 0.Constraints:
1 <= n <= 200.
At first, you might think about generating all possible binary trees with n nodes and then filtering out the ones that are not full. However, that approach is inefficient, as the number of binary trees grows rapidly with n.
Instead, we can use the definition of a full binary tree to build only valid trees:
n is even, there are no possible full binary trees.
We can recursively construct all trees by:
We use a recursive, memoized approach to generate all full binary trees:
n == 1, the only possible tree is a single node. Return a list containing a single-node tree.
n is even, return an empty list (since full binary trees can only have an odd number of nodes).
left_nodes from 1 to n-2 (step 2), do:right_nodes = n - 1 - left_nodes.left_nodes and right_nodes nodes.n so that we do not recompute the same result multiple times.
n.
This approach ensures that:
Let's walk through the case where n = 5:
n is odd and greater than 1, we try all possible splits:
left_nodes and right_nodes:
left_nodes = 1, only one tree: single node.
right_nodes = 3:
1|1 (since 3-1=2, only odd split is 1 and 1).left_nodes = 3 and right_nodes = 1, swap the above.
Brute-force Approach:
n (super-exponential, as the number of binary trees grows as Catalan numbers).n nodes is the (n-1)/2th Catalan number, which grows exponentially but much slower than the number of all binary trees.
C_n), where C_n is the Catalan number for n nodes.
C_n) for storing all trees and the memoization cache.
For n <= 20, this approach is efficient and practical.
To generate all possible full binary trees with n nodes:
n (since full binary trees have an odd number of nodes).from typing import List, Optional
# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]:
memo = {}
def build(n):
if n in memo:
return memo[n]
if n == 1:
return [TreeNode(0)]
if n % 2 == 0:
return []
res = []
for left_nodes in range(1, n, 2):
right_nodes = n - 1 - left_nodes
for left in build(left_nodes):
for right in build(right_nodes):
root = TreeNode(0)
root.left = left
root.right = right
res.append(root)
memo[n] = res
return res
return build(n)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
unordered_map<int, vector<TreeNode*>> memo;
vector<TreeNode*> allPossibleFBT(int n) {
if (memo.count(n)) return memo[n];
vector<TreeNode*> res;
if (n == 1) {
res.push_back(new TreeNode(0));
return res;
}
if (n % 2 == 0) return res;
for (int left_nodes = 1; left_nodes < n; left_nodes += 2) {
int right_nodes = n - 1 - left_nodes;
vector<TreeNode*> left_trees = allPossibleFBT(left_nodes);
vector<TreeNode*> right_trees = allPossibleFBT(right_nodes);
for (auto left : left_trees) {
for (auto right : right_trees) {
TreeNode* root = new TreeNode(0);
root->left = left;
root->right = right;
res.push_back(root);
}
}
}
memo[n] = res;
return res;
}
};
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() { val = 0; }
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
import java.util.*;
class Solution {
private Map<Integer, List<TreeNode>> memo = new HashMap<>();
public List<TreeNode> allPossibleFBT(int n) {
if (memo.containsKey(n)) return memo.get(n);
List<TreeNode> res = new ArrayList<>();
if (n == 1) {
res.add(new TreeNode(0));
return res;
}
if (n % 2 == 0) return res;
for (int left_nodes = 1; left_nodes < n; left_nodes += 2) {
int right_nodes = n - 1 - left_nodes;
List<TreeNode> left_trees = allPossibleFBT(left_nodes);
List<TreeNode> right_trees = allPossibleFBT(right_nodes);
for (TreeNode left : left_trees) {
for (TreeNode right : right_trees) {
TreeNode root = new TreeNode(0);
root.left = left;
root.right = right;
res.add(root);
}
}
}
memo.put(n, res);
return res;
}
}
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {number} n
* @return {TreeNode[]}
*/
var allPossibleFBT = function(n) {
const memo = {};
function build(n) {
if (memo[n]) return memo[n];
if (n === 1) return [new TreeNode(0)];
if (n % 2 === 0) return [];
let res = [];
for (let left_nodes = 1; left_nodes < n; left_nodes += 2) {
let right_nodes = n - 1 - left_nodes;
let left_trees = build(left_nodes);
let right_trees = build(right_nodes);
for (let left of left_trees) {
for (let right of right_trees) {
let root = new TreeNode(0);
root.left = left;
root.right = right;
res.push(root);
}
}
}
memo[n] = res;
return res;
}
return build(n);
};