Before attempting this problem, you should be comfortable with:
Binary Trees - Understanding tree structure and node creation
Recursion - Breaking down problems by combining solutions to subproblems
Dynamic Programming (Memoization) - Caching results to avoid redundant computation
1. Recursion
Intuition
A full binary tree has every node with either 0 or 2 children. If we have n nodes, one becomes the root, and we split the remaining n-1 nodes between the left and right subtrees. Each subtree must also be a full binary tree.
We try all possible ways to distribute n-1 nodes between left and right. For each valid split, we recursively generate all possible left subtrees and all possible right subtrees, then combine each left-right pair under a new root.
Algorithm
Base cases: If n == 0, return an empty list. If n == 1, return a list with a single node.
For l from 0 to n-1:
Set r = n - 1 - l (remaining nodes for the right subtree).
Recursively get all full binary trees with l nodes for the left.
Recursively get all full binary trees with r nodes for the right.
For each combination of left and right subtree, create a new root and add it to the res.
# 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 = rightclassSolution:defallPossibleFBT(self, n:int)-> List[Optional[TreeNode]]:defbacktrack(n):if n ==0:return[]if n ==1:return[TreeNode(0)]
res =[]for l inrange(n):
r = n -1- l
leftTrees, rightTrees = backtrack(l), backtrack(r)for t1 in leftTrees:for t2 in rightTrees:
res.append(TreeNode(0, t1, t2))return res
return backtrack(n)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/publicclassSolution{publicList<TreeNode>allPossibleFBT(int n){returnbacktrack(n);}privateList<TreeNode>backtrack(int n){if(n ==0){returnnewArrayList<>();}if(n ==1){returnArrays.asList(newTreeNode(0));}List<TreeNode> res =newArrayList<>();for(int l =0; l < n; l++){int r = n -1- l;List<TreeNode> leftTrees =backtrack(l);List<TreeNode> rightTrees =backtrack(r);for(TreeNode t1 : leftTrees){for(TreeNode t2 : rightTrees){
res.add(newTreeNode(0, t1, t2));}}}return res;}}
/**
* Definition for a binary tree node.
* class TreeNode {
* constructor(val = 0, left = null, right = null) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/classSolution{/**
* @param {number} n
* @return {TreeNode[]}
*/allPossibleFBT(n){constbacktrack=(n)=>{if(n ===0){return[];}if(n ===1){return[newTreeNode(0)];}let res =[];for(let l =0; l < n; l++){let r = n -1- l;let leftTrees =backtrack(l);let rightTrees =backtrack(r);for(let t1 of leftTrees){for(let t2 of rightTrees){
res.push(newTreeNode(0, t1, t2));}}}return res;};returnbacktrack(n);}}
/**
* Definition for a binary tree node.
* public class TreeNode {
* public int val;
* public TreeNode left;
* public TreeNode right;
* public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/publicclassSolution{publicIList<TreeNode>AllPossibleFBT(int n){returnBacktrack(n);}privateIList<TreeNode>Backtrack(int n){if(n ==0){returnnewList<TreeNode>();}if(n ==1){returnnewList<TreeNode>{newTreeNode(0)};}List<TreeNode> res =newList<TreeNode>();for(int l =0; l < n; l++){int r = n -1- l;IList<TreeNode> leftTrees =Backtrack(l);IList<TreeNode> rightTrees =Backtrack(r);foreach(TreeNode t1 in leftTrees){foreach(TreeNode t2 in rightTrees){
res.Add(newTreeNode(0, t1, t2));}}}return res;}}
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/funcallPossibleFBT(n int)[]*TreeNode {var backtrack func(n int)[]*TreeNode
backtrack =func(n int)[]*TreeNode {if n ==0{return[]*TreeNode{}}if n ==1{return[]*TreeNode{{Val:0}}}
res :=[]*TreeNode{}for l :=0; l < n; l++{
r := n -1- l
leftTrees :=backtrack(l)
rightTrees :=backtrack(r)for_, t1 :=range leftTrees {for_, t2 :=range rightTrees {
res =append(res,&TreeNode{Val:0, Left: t1, Right: t2})}}}return res
}returnbacktrack(n)}
/**
* Example:
* var ti = TreeNode(5)
* var v = ti.`val`
* Definition for a binary tree node.
* class TreeNode(var `val`: Int) {
* var left: TreeNode? = null
* var right: TreeNode? = null
* }
*/class Solution {funallPossibleFBT(n: Int): List<TreeNode?>{funbacktrack(n: Int): List<TreeNode?>{if(n ==0)returnemptyList()if(n ==1)returnlistOf(TreeNode(0))val res = mutableListOf<TreeNode?>()for(l in0 until n){val r = n -1- l
val leftTrees =backtrack(l)val rightTrees =backtrack(r)for(t1 in leftTrees){for(t2 in rightTrees){
res.add(TreeNode(0).apply{
left = t1
right = t2
})}}}return res
}returnbacktrack(n)}}
/**
* Definition for a binary tree node.
* public class TreeNode {
* public var val: Int
* public var left: TreeNode?
* public var right: TreeNode?
* public init() { self.val = 0; self.left = nil; self.right = nil; }
* public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; }
* public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) {
* self.val = val
* self.left = left
* self.right = right
* }
* }
*/classSolution{funcallPossibleFBT(_ n:Int)->[TreeNode?]{funcbacktrack(_ n:Int)->[TreeNode?]{if n ==0{return[]}if n ==1{return[TreeNode(0)]}var res =[TreeNode?]()for l in0..<n {let r = n -1- l
let leftTrees =backtrack(l)let rightTrees =backtrack(r)for t1 in leftTrees {for t2 in rightTrees {
res.append(TreeNode(0, t1, t2))}}}return res
}returnbacktrack(n)}}
Time & Space Complexity
Time complexity: O(2n)
Space complexity: O(n∗2n)
2. Recursion (Optimal)
Intuition
A full binary tree with n nodes only exists when n is odd. Every full binary tree has one root plus pairs of nodes in the subtrees, so the total must be odd. This lets us prune impossible cases immediately.
Additionally, we only need to try odd values for the left subtree size since each subtree must also form a valid full binary tree (requiring an odd count). This cuts the search space roughly in half.
Algorithm
If n is even, return an empty list (impossible to form a full binary tree).
If n == 1, return a list with a single node.
For left from 1 to n-1, stepping by 2 (odd values only):
Recursively get all full binary trees with left nodes.
Recursively get all full binary trees with n - 1 - left nodes.
Combine each pair under a new root and add to the res.
# 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 = rightclassSolution:defallPossibleFBT(self, n:int)-> List[Optional[TreeNode]]:if n %2==0:return[]if n ==1:return[TreeNode(0)]
res =[]for left inrange(1, n,2):
leftSubTree = self.allPossibleFBT(left)
rightSubTree = self.allPossibleFBT(n -1- left)for l in leftSubTree:for r in rightSubTree:
root = TreeNode(0, l, r)
res.append(root)return res
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/publicclassSolution{publicList<TreeNode>allPossibleFBT(int n){if(n %2==0){returnnewArrayList<>();}if(n ==1){returnArrays.asList(newTreeNode(0));}List<TreeNode> res =newArrayList<>();for(int left =1; left < n; left +=2){List<TreeNode> leftSubTree =allPossibleFBT(left);List<TreeNode> rightSubTree =allPossibleFBT(n -1- left);for(TreeNode l : leftSubTree){for(TreeNode r : rightSubTree){TreeNode root =newTreeNode(0, l, r);
res.add(root);}}}return res;}}
/**
* 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) {}
* };
*/classSolution{public:
vector<TreeNode*>allPossibleFBT(int n){if(n %2==0){return{};}if(n ==1){return{newTreeNode(0)};}
vector<TreeNode*> res;for(int left =1; left < n; left +=2){
vector<TreeNode*> leftSubTree =allPossibleFBT(left);
vector<TreeNode*> rightSubTree =allPossibleFBT(n -1- left);for(auto& l : leftSubTree){for(auto& r : rightSubTree){
TreeNode* root =newTreeNode(0, l, r);
res.push_back(root);}}}return res;}};
/**
* Definition for a binary tree node.
* class TreeNode {
* constructor(val = 0, left = null, right = null) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/classSolution{/**
* @param {number} n
* @return {TreeNode[]}
*/allPossibleFBT(n){if(n %2===0){return[];}if(n ===1){return[newTreeNode(0)];}let res =[];for(let left =1; left < n; left +=2){let leftSubTree =this.allPossibleFBT(left);let rightSubTree =this.allPossibleFBT(n -1- left);for(let l of leftSubTree){for(let r of rightSubTree){let root =newTreeNode(0, l, r);
res.push(root);}}}return res;}}
publicclassSolution{publicIList<TreeNode>AllPossibleFBT(int n){if(n %2==0){returnnewList<TreeNode>();}if(n ==1){returnnewList<TreeNode>{newTreeNode(0)};}List<TreeNode> res =newList<TreeNode>();for(int left =1; left < n; left +=2){IList<TreeNode> leftSubTree =AllPossibleFBT(left);IList<TreeNode> rightSubTree =AllPossibleFBT(n -1- left);foreach(TreeNode l in leftSubTree){foreach(TreeNode r in rightSubTree){
res.Add(newTreeNode(0, l, r));}}}return res;}}
funcallPossibleFBT(n int)[]*TreeNode {if n%2==0{return[]*TreeNode{}}if n ==1{return[]*TreeNode{{Val:0}}}
res :=[]*TreeNode{}for left :=1; left < n; left +=2{
leftSubTree :=allPossibleFBT(left)
rightSubTree :=allPossibleFBT(n -1- left)for_, l :=range leftSubTree {for_, r :=range rightSubTree {
res =append(res,&TreeNode{Val:0, Left: l, Right: r})}}}return res
}
class Solution {funallPossibleFBT(n: Int): List<TreeNode?>{if(n %2==0)returnemptyList()if(n ==1)returnlistOf(TreeNode(0))val res = mutableListOf<TreeNode?>()for(left in1 until n step 2){val leftSubTree =allPossibleFBT(left)val rightSubTree =allPossibleFBT(n -1- left)for(l in leftSubTree){for(r in rightSubTree){
res.add(TreeNode(0).apply{this.left = l
right = r
})}}}return res
}}
classSolution{funcallPossibleFBT(_ n:Int)->[TreeNode?]{if n %2==0{return[]}if n ==1{return[TreeNode(0)]}var res =[TreeNode?]()forleftinstride(from:1, to: n, by:2){let leftSubTree =allPossibleFBT(left)let rightSubTree =allPossibleFBT(n -1-left)for l in leftSubTree {for r in rightSubTree {
res.append(TreeNode(0, l, r))}}}return res
}}
Time & Space Complexity
Time complexity: O(2n)
Space complexity: O(n∗2n)
3. Dynamic Programming (Top-Down)
Intuition
The recursive solution recomputes the same subproblems multiple times. For example, when building trees of size 7, we compute trees of size 3 several times across different branches.
By caching results in a hash map or array, we ensure each subproblem is solved only once. The first time we compute all trees for a given n, we store them. Future calls simply return the cached dp result.
Algorithm
Create a memoization map dp to store results for each n.
# 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 = rightclassSolution:defallPossibleFBT(self, n:int)-> List[Optional[TreeNode]]:
dp ={}defdfs(n):if n %2==0:return[]if n ==1:return[TreeNode(0)]if n in dp:return dp[n]
res =[]for left inrange(1, n,2):
leftSubTree = dfs(left)
rightSubTree = dfs(n -1- left)for l in leftSubTree:for r in rightSubTree:
res.append(TreeNode(0, l, r))
dp[n]= res
return res
return dfs(n)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/publicclassSolution{privateList<TreeNode>[] dp;publicList<TreeNode>allPossibleFBT(int n){
dp =newArrayList[n +1];returndfs(n);}privateList<TreeNode>dfs(int n){if(n %2==0){returnnewArrayList<>();}if(n ==1){returnArrays.asList(newTreeNode(0));}if(dp[n]!=null){return dp[n];}List<TreeNode> res =newArrayList<>();for(int left =1; left < n; left +=2){List<TreeNode> leftSubTree =dfs(left);List<TreeNode> rightSubTree =dfs(n -1- left);for(TreeNode l : leftSubTree){for(TreeNode r : rightSubTree){
res.add(newTreeNode(0, l, r));}}}return dp[n]= res;}}
/**
* 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) {}
* };
*/classSolution{private:
vector<vector<TreeNode*>> dp;public:
vector<TreeNode*>allPossibleFBT(int n){
dp.resize(n +1);returndfs(n);}
vector<TreeNode*>dfs(int n){if(n %2==0){return{};}if(n ==1){return{newTreeNode(0)};}if(!dp[n].empty()){return dp[n];}
vector<TreeNode*> res;for(int left =1; left < n; left +=2){
vector<TreeNode*> leftSubTree =dfs(left);
vector<TreeNode*> rightSubTree =dfs(n -1- left);for(auto& l : leftSubTree){for(auto& r : rightSubTree){
res.push_back(newTreeNode(0, l, r));}}}return dp[n]= res;}};
/**
* Definition for a binary tree node.
* class TreeNode {
* constructor(val = 0, left = null, right = null) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/classSolution{/**
* @param {number} n
* @return {TreeNode[]}
*/allPossibleFBT(n){let dp =newArray(n +1);constdfs=(n)=>{if(n %2===0){return[];}if(n ===1){return[newTreeNode(0)];}if(dp[n]){return dp[n];}let res =[];for(let left =1; left < n; left +=2){let leftSubTree =dfs(left);let rightSubTree =dfs(n -1- left);for(let t1 of leftSubTree){for(let t2 of rightSubTree){
res.push(newTreeNode(0, t1, t2));}}}return(dp[n]= res);};returndfs(n);}}
publicclassSolution{privateIList<TreeNode>[] dp;publicIList<TreeNode>AllPossibleFBT(int n){
dp =newIList<TreeNode>[n +1];returnDfs(n);}privateIList<TreeNode>Dfs(int n){if(n %2==0){returnnewList<TreeNode>();}if(n ==1){returnnewList<TreeNode>{newTreeNode(0)};}if(dp[n]!=null){return dp[n];}List<TreeNode> res =newList<TreeNode>();for(int left =1; left < n; left +=2){IList<TreeNode> leftSubTree =Dfs(left);IList<TreeNode> rightSubTree =Dfs(n -1- left);foreach(TreeNode l in leftSubTree){foreach(TreeNode r in rightSubTree){
res.Add(newTreeNode(0, l, r));}}}
dp[n]= res;return res;}}
funcallPossibleFBT(n int)[]*TreeNode {
dp :=make([][]*TreeNode, n+1)var dfs func(n int)[]*TreeNode
dfs =func(n int)[]*TreeNode {if n%2==0{return[]*TreeNode{}}if n ==1{return[]*TreeNode{{Val:0}}}if dp[n]!=nil{return dp[n]}
res :=[]*TreeNode{}for left :=1; left < n; left +=2{
leftSubTree :=dfs(left)
rightSubTree :=dfs(n -1- left)for_, l :=range leftSubTree {for_, r :=range rightSubTree {
res =append(res,&TreeNode{Val:0, Left: l, Right: r})}}}
dp[n]= res
return res
}returndfs(n)}
class Solution {funallPossibleFBT(n: Int): List<TreeNode?>{val dp = arrayOfNulls<List<TreeNode?>>(n +1)fundfs(n: Int): List<TreeNode?>{if(n %2==0)returnemptyList()if(n ==1)returnlistOf(TreeNode(0))if(dp[n]!=null)return dp[n]!!val res = mutableListOf<TreeNode?>()for(left in1 until n step 2){val leftSubTree =dfs(left)val rightSubTree =dfs(n -1- left)for(l in leftSubTree){for(r in rightSubTree){
res.add(TreeNode(0).apply{this.left = l
right = r
})}}}
dp[n]= res
return res
}returndfs(n)}}
classSolution{funcallPossibleFBT(_ n:Int)->[TreeNode?]{var dp =[[TreeNode?]?](repeating:nil, count: n +1)funcdfs(_ n:Int)->[TreeNode?]{if n %2==0{return[]}if n ==1{return[TreeNode(0)]}iflet cached = dp[n]{return cached }var res =[TreeNode?]()forleftinstride(from:1, to: n, by:2){let leftSubTree =dfs(left)let rightSubTree =dfs(n -1-left)for l in leftSubTree {for r in rightSubTree {
res.append(TreeNode(0, l, r))}}}
dp[n]= res
return res
}returndfs(n)}}
Time & Space Complexity
Time complexity: O(2n)
Space complexity: O(n∗2n)
4. Dynamic Programming (Bottom-Up)
Intuition
Instead of recursing from n down and caching, we can build solutions bottom-up. We start with the base case (n=1), then iteratively compute solutions for n=3, 5, 7, ... up to the target.
For each odd value, we combine previously computed smaller trees to form larger ones. Since we only ever need results for smaller odd numbers, and we compute them in order, all dependencies are satisfied when we need them.
Algorithm
If n is even, return an empty list.
Create an array dp where dp[i] will store all full binary trees with i nodes.
Initialize dp[1] with a single node.
For nodes from 3 to n, stepping by 2:
For left from 1 to nodes-1, stepping by 2:
Set right = nodes - 1 - left.
For each tree in dp[left] and each tree in dp[right]:
Create a new root combining them and add to dp[nodes].
# 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 = rightclassSolution:defallPossibleFBT(self, n:int)-> List[Optional[TreeNode]]:if n %2==0:return[]
dp =[[]for _ inrange(n +1)]
dp[1]=[TreeNode(0)]for nodes inrange(3, n +1,2):
res =[]for left inrange(1, nodes,2):
right = nodes -1- left
for t1 in dp[left]:for t2 in dp[right]:
res.append(TreeNode(0, t1, t2))
dp[nodes]= res
return dp[n]
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/publicclassSolution{publicList<TreeNode>allPossibleFBT(int n){if(n %2==0){returnnewArrayList<>();}List<TreeNode>[] dp =newArrayList[n +1];for(int i =0; i <= n; i++){
dp[i]=newArrayList<>();}
dp[1].add(newTreeNode(0));for(int nodes =3; nodes <= n; nodes +=2){List<TreeNode> res =newArrayList<>();for(int left =1; left < nodes; left +=2){int right = nodes -1- left;for(TreeNode t1 : dp[left]){for(TreeNode t2 : dp[right]){
res.add(newTreeNode(0, t1, t2));}}}
dp[nodes]= res;}return dp[n];}}
/**
* Definition for a binary tree node.
* class TreeNode {
* constructor(val = 0, left = null, right = null) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/classSolution{/**
* @param {number} n
* @return {TreeNode[]}
*/allPossibleFBT(n){if(n %2===0){return[];}let dp = Array.from({length: n +1},()=>[]);
dp[1]=[newTreeNode(0)];for(let nodes =3; nodes <= n; nodes +=2){let res =[];for(let left =1; left < nodes; left +=2){let right = nodes -1- left;for(let t1 of dp[left]){for(let t2 of dp[right]){
res.push(newTreeNode(0, t1, t2));}}}
dp[nodes]= res;}return dp[n];}}
publicclassSolution{publicIList<TreeNode>AllPossibleFBT(int n){if(n %2==0){returnnewList<TreeNode>();}IList<TreeNode>[] dp =newIList<TreeNode>[n +1];for(int i =0; i <= n; i++){
dp[i]=newList<TreeNode>();}
dp[1].Add(newTreeNode(0));for(int nodes =3; nodes <= n; nodes +=2){List<TreeNode> res =newList<TreeNode>();for(int left =1; left < nodes; left +=2){int right = nodes -1- left;foreach(TreeNode t1 in dp[left]){foreach(TreeNode t2 in dp[right]){
res.Add(newTreeNode(0, t1, t2));}}}
dp[nodes]= res;}return dp[n];}}
funcallPossibleFBT(n int)[]*TreeNode {if n%2==0{return[]*TreeNode{}}
dp :=make([][]*TreeNode, n+1)for i :=range dp {
dp[i]=[]*TreeNode{}}
dp[1]=[]*TreeNode{{Val:0}}for nodes :=3; nodes <= n; nodes +=2{
res :=[]*TreeNode{}for left :=1; left < nodes; left +=2{
right := nodes -1- left
for_, t1 :=range dp[left]{for_, t2 :=range dp[right]{
res =append(res,&TreeNode{Val:0, Left: t1, Right: t2})}}}
dp[nodes]= res
}return dp[n]}
class Solution {funallPossibleFBT(n: Int): List<TreeNode?>{if(n %2==0)returnemptyList()val dp = Array<MutableList<TreeNode?>>(n +1){mutableListOf()}
dp[1].add(TreeNode(0))for(nodes in3..n step 2){val res = mutableListOf<TreeNode?>()for(left in1 until nodes step 2){val right = nodes -1- left
for(t1 in dp[left]){for(t2 in dp[right]){
res.add(TreeNode(0).apply{this.left = t1
this.right = t2
})}}}
dp[nodes]= res
}return dp[n]}}
classSolution{funcallPossibleFBT(_ n:Int)->[TreeNode?]{if n %2==0{return[]}var dp =[[TreeNode?]](repeating:[], count: n +1)
dp[1]=[TreeNode(0)]for nodes instride(from:3, through: n, by:2){var res =[TreeNode?]()forleftinstride(from:1, to: nodes, by:2){letright= nodes -1-leftfor t1 in dp[left]{for t2 in dp[right]{
res.append(TreeNode(0, t1, t2))}}}
dp[nodes]= res
}return dp[n]}}
Time & Space Complexity
Time complexity: O(2n)
Space complexity: O(n∗2n)
Common Pitfalls
Forgetting That Full Binary Trees Require Odd Node Counts
A full binary tree can only exist when n is odd. Each node either has 0 or 2 children, so starting with 1 root and adding pairs means the total is always odd. Failing to check this leads to wasted computation or incorrect results.
# Wrong: missing the odd checkdefallPossibleFBT(n):if n ==1:return[TreeNode(0)]# Will waste time on even n values
Reusing Tree Nodes Across Different Results
When combining left and right subtrees, you must create a new root node for each combination. Reusing the same node object causes all trees to share structure, corrupting the results.
# Wrong: reusing same root node
root = TreeNode(0)for l in leftTrees:for r in rightTrees:
root.left, root.right = l, r
res.append(root)# All entries point to same node!
Iterating Over Even Values for Subtree Sizes
In a full binary tree, both left and right subtrees must also be full binary trees, meaning they need odd node counts. Iterating over all values instead of only odd values wastes time and produces empty results for even sizes.
# Wrong: iterating all valuesfor left inrange(1, n):# Includes even values...# Correct: step by 2 to only use odd valuesfor left inrange(1, n,2):...