LeetCode #617 Easy

Merge Two Binary Trees

Overlay two binary trees, summing values where both trees have a node.

treedfsrecursion
Open on LeetCode ↗
02

Intuition

The tempting shortcut is to return None the moment either root is None -- but that is wrong: if root1 is None, the correct answer is the WHOLE of root2's subtree carried over as-is, not nothing. Only when BOTH nodes are None does the merge truly produce None. So the recursion needs three cases, not two: both missing means None, exactly one missing means take that one whole, and both present means sum the values and merge children recursively. The surviving subtree is not touched, just reattached.

How to spot this pattern

Recurse in parallel down both trees. When one side is null the other subtree is grafted in whole — no further recursion needed, since there's nothing to merge it with. That early return is what keeps the traversal proportional to the overlap.

03

Approach

1

Handle the two 'one missing' cases explicitly

if not root1: return root2, and if not root2: return root1. These return the entire remaining subtree unchanged -- no further recursion needed on that branch.

2

Both present: sum and recurse

Create (or reuse) a node with root1.val + root2.val, then merge(root1.left, root2.left) and merge(root1.right, root2.right).

3

Both missing

If both root1 and root2 are None, return None -- this is the true base case, checked implicitly by both single-null checks passing through None on each side.

04

Solution & live demo

1class Solution:
2 def mergeTrees(self, root1, root2):
3 if not root1 and not root2:
4 return None
5 if not root1:
6 return root2
7 if not root2:
8 return root1
9 merged = TreeNode(root1.val + root2.val)
10 merged.left = self.mergeTrees(root1.left, root2.left)
11 merged.right = self.mergeTrees(root1.right, root2.right)
12 return merged
05

Common pitfalls

Continuing to recurse after one side is null

✗ Wrong
if not root1:
    merged = TreeNode(root2.val)
    merged.left = self.mergeTrees(None, root2.left)
✓ Right
if not root1:
    return root2

Rebuilding the remaining subtree node by node is pure waste — it's already exactly the answer for that branch. Returning it directly is both faster and shorter.

Testing the null cases in the wrong order

✗ Wrong
if not root1: return root2
if not root1 and not root2: return None
✓ Right
if not root1 and not root2: return None
if not root1: return root2

The second condition is unreachable once the first has fired. As written it happens to be harmless — root2 is null so returning it is still correct — but the ordering hides the intent and breaks if the branches ever diverge.

Mutating root1 in place

✗ Wrong
root1.val += root2.val
return root1
✓ Right
merged = TreeNode(root1.val + root2.val)

Accepted by most judges, but it destroys the caller's input tree. Building a new node leaves both arguments intact, which matters if either is reused.

06

Edge cases

Both trees empty

Falls through both null checks and returns None.

One tree empty entirely

The other tree is returned unchanged, no merging performed.

Overlapping structure but different depths

Where one side runs out first, remaining nodes are reattached as-is via the single-null case.

Negative values

Sum still works correctly; no special casing needed.

07

Complexity

Time
O(min(m, n))
Space
O(min(m, n))
Recursion stops at whichever tree runs out of nodes first.