LeetCode 105: Build Tree from Preorder Inorder

Binary trees from traversals sound smart. Until the code's sloppy recursion bites back with quadratic doom.

LeetCode 105: Tree-Building Hack That's Half-Baked — theAIcatchup

Key Takeaways

  • Default solution is O(n²)—fine for interviews, fatal for scale.
  • Hashmap indices make it O(n) time and space.
  • LeetCode 105 tests core recursion; optimize to impress.

Trees don’t build themselves.

LeetCode 105 shoves preorder and inorder arrays at you—rebuild the binary tree or bust. Simple, right? Ha. It’s recursion’s playground, where rookies trip and “seniors” pretend it’s elegant.

LeetCode 105: What Fresh Hell Is This?

Picture this: preorder spits roots first—left subtree, then right. Inorder? Left, root, right. Mash ‘em together recursively. Root from preorder[0]. Find it in inorder. Split left/right subarrays. Repeat till empty.

Given two arrays representing preorder and inorder traversals of a binary tree, reconstruct and return the original binary tree.

That’s the pitch. Clean. But peek under the hood.

Here’s the code they flaunt:

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if not preorder or not inorder:
            return None
        root_val = preorder.pop(0)
        root = TreeNode(root_val)
        root_index = inorder.index(root_val)
        root.left = self.buildTree(preorder, inorder[:root_index])
        root.right = self.buildTree(preorder, inorder[root_index + 1 :])
        return root

Pops preorder head. Indexes inorder for split. Recurses. Returns tree. Time: O(n²). Space: O(n). Cute on paper.

But.

That inorder.index(root_val)? Linear scan. Every level. n times. Boom—quadratic hell for n=1000. Interviews love it. Real code? Laughs you out.

Why LeetCode 105’s Solution Sucks

Short answer: laziness. They pop preorder—mutates it, sneaky but fine. But indexing? Amateur hour. No hashmap for root positions. It’s 1995 all over again, before we wised up.

Visualize with TraceLit, their toy. Step through. See the tree sprout. Left subtree from inorder[:index], right from [index+1:]. Preorder advances naturally—post-pop. Elegant? Sure, if n<100.

Here’s the thing. Interviews cap inputs small. LeetCode? n<=3000, but hidden tests spike. Quadratic tanks it. I’ve seen candidates beam, submit, then TLE. Dry humor: their face? Priceless.

Unique twist nobody mentions: this mirrors 1970s LISP tree parsers—pre-hashmap era. Knuth would’ve snorted. We ditched that for O(n) maps decades ago. LeetCode clings like a bad ex.

And popping preorder? Side-effect city. Pure functionalists cringe. Pass indices instead, you cowards.

Is O(n²) Good Enough for Interviews?

Yes. Barely. FAANG gatekeepers want the idea, not perfection. Nail recursion, splits—you pass. Optimize later.

But predict this: LLMs kill LeetCode worship. Soon, “solve 105” becomes “prompt GPT.” Interviews shift to system design. Trees? Table stakes, forgotten.

Don’t buy the hype. TraceLit visualizer? Gimmick. Step through yourself—pen, paper. Builds muscle.

Deeper dive: duplicates? Problem assumes unique vals. Real trees? Multisets. Crashes hard. Addendum: use hash of indices, but preorder pop assumes order. Messy.

Improved version—because I’m not lazy:

Precompute inorder index hashmap. O(n) build. Then recurse with indices, no pops/slices. Slices copy—extra O(n²) space hidden. Indices only: pure O(n).

def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
    if not preorder: return None
    idx_map = {val: i for i, val in enumerate(inorder)}
    def helper(pre_start, pre_end, in_start, in_end):
        if pre_start > pre_end: return None
        root_val = preorder[pre_start]
        root = TreeNode(root_val)
        root_idx = idx_map[root_val]
        left_size = root_idx - in_start
        root.left = helper(pre_start+1, pre_start+left_size, in_start, root_idx-1)
        root.right = helper(pre_start+left_size+1, pre_end, root_idx+1, in_end)
        return root
    return helper(0, len(preorder)-1, 0, len(inorder)-1)

See? No mutations. No scans. O(n) time, O(n) space. LeetCode accepts both. Pick your poison.

Critique their PR spin: “Step-by-step visual trace.” Yawn. Everyone’s seen it. Medium tags—Binary Tree | Recursion | Array | Tree Construction—like SEO vomit.

Why Does LeetCode 105 Matter for Coders?

Tests tree intuition. Pre/inorder complementarity. Few problems pack recursion + arrays + trees so tight.

Master it, unlock 106 (in/post), 114 (flatten). Pattern city.

But call out the corporate game: LeetCode grinds souls for Big Tech. 105? Mid-tier medium. Prep it, sure. Obsess? Waste.

Real world: rarely raw traversals. Deserializers handle it. Know the math—good. Implement daily? Nah.

Wander a bit: remember AVL self-balancing? This assumes complete trees. Skewed inputs? Stack overflow risk, deep recursion.

Python’s fine—sys.setrecursionlimit. Prod? Iterative stack. Overkill here.


🧬 Related Insights

Frequently Asked Questions

How does LeetCode 105 reconstruct the tree?

Preorder picks root. Inorder splits subtrees. Recurse till done.

What’s wrong with LeetCode 105’s default solution?

O(n²) from repeated index searches. Use hashmap for O(n).

Does LeetCode 105 handle duplicates?

No. Assumes unique values. Real fix: indices only.

Marcus Rivera
Written by

Tech journalist covering AI business and enterprise adoption. 10 years in B2B media.

Frequently asked questions

How does LeetCode 105 reconstruct the tree?
Preorder picks root. Inorder splits subtrees. Recurse till done.
What's wrong with LeetCode 105's default solution?
O(n²) from repeated index searches. Use hashmap for O(n).
Does LeetCode 105 handle duplicates?
No. Assumes unique values. Real fix: indices only.

Worth sharing?

Get the best AI stories of the week in your inbox — no noise, no spam.

Originally reported by Dev.to

Stay in the loop

The week's most important stories from theAIcatchup, delivered once a week.