The O(n) Club: All Possible Full Binary Trees — Recursion Without Regrets
The O(n) Club: All Possible Full Binary Trees — Recursion Without Regrets
- 2 min read

The O(n) Club: All Possible Full Binary Trees — Recursion Without Regrets

On this page
Introduction

The O(n) Club: All Possible Full Binary Trees — Recursion Without Regrets

⚡ TL;DR

Want every structurally unique full binary tree for an odd number n? Just recurse your heart out: split the remaining nodes after the root into every odd pair, join all subtree combinations, and — please — memoize! Don’t even look at even n, unless you hate joy.
Here’s the totally unoptimized Java for masochists:

🧠 How Devs Usually Mess This Up

Classic rookie moves: Trying even n (nope), confusing ‘full’ with ‘complete’ or ‘perfect’ (nope), or thinking nodes’ values could possibly matter (shocker: they don’t). Pro tip: If you’re not memoizing, you’re just mining Bitcoin for the heating bill — this grows fast. Seriously.

🔍 What’s Actually Going On

Each root gets exactly two subtrees (unless it’s solo) — exactly like handing out two cupcakes to every guest, until nobody’s left standing but solitary crumbs. For every possible split (odd numbers only!), recursively build left/right trees, mash them together under a new root. Oh, and write down trees you’ve already built, unless you want infinite recursion to become your legacy.

🛠️ PseudoCode

Store & return:

memo[n] = result;
return result;

Memoized? Good. Ship it.

Get all combos: For each possible left and right subtree, combine:

for each left : leftTrees
 for each right : rightTrees
   root = TreeNode(0)
   root.left = left
   root.right = right
   result.add(root)

It’s tree buffet time. Take every combo.

Recursion on odd splits: For odd left/right sizes…

for (left = 1; left < n; left += 2)

There’s always a root node in the middle — leave room for two legit children.

Memoization: If you already solved for n, return the answer.

if (memo contains n) return memo[n];

Save your sanity, and RAM.

Base case: If n == 1, return a single-node tree.

if (n == 1) return [TreeNode(0)];

Single node? Congrats, it’s a tree.

💻 The Code

class TreeNode {
    int val;
    TreeNode left, right;
    TreeNode(int val) { this.val = val; }
}
 class Solution {
    Map<integer list>> memo = new HashMap<>();
    public List
<treenode> allPossibleFBT(int n) {
        if (n % 2 == 0) return List.of(); // No full binary for even n
        if (n == 1) return List.of(new TreeNode(0));
        if (memo.containsKey(n)) return memo.get(n);
        List
<treenode> out = new ArrayList<>();
        for (int left = 1; left < n; left += 2) {
            int right = n - 1 - left;
            for (TreeNode l : allPossibleFBT(left)) {
                for (TreeNode r : allPossibleFBT(right)) {
                    TreeNode root = new TreeNode(0);
                    root.left = l;
                    root.right = r;
                    out.add(root);
                }
            }
        }
        memo.put(n, out);
        return out;
    }
}
</treenode></treenode></integer>

⚠️ Pitfalls, Traps & Runtime Smacks

  • Even n? Instantly returns nothing. Full = always odd. No fudge room.
  • Tree shapes matter, not node values. They’re all zero, so structure is king.
  • Memoize, or cry endlessly. Naive recursion goes boom for big n.
  • ‘Full’ ≠ ‘Complete’ ≠ ‘Perfect’: Interviewers *love* to trip you up here.
  • Complexity: Exponential trees, exponential RAM used. But with memoization, you’ll actually see some answers before Haskell is cool again.

🧠 Interviewer Brain-Tattoo

“Look, if you’re generating the same subtree twice, you’re not optimizing — you’re just stubborn. Memoize or brace for a recursive apocalypse.”