~20 minutes · Day 33 · simultaneous DFS
Tonight's interview move is small but important: sometimes one recursive call is not enough. In Same Tree, the question is not "what is the answer for one subtree?" It is "do these two current positions describe the same tree?" That means every step carries two nodes, not one.
Two trees are identical iff their roots match and both pairs of subtrees are identical — compare them in lockstep.
That sentence is the whole pattern. Do not try to remember a special trick for Same Tree. Remember the lockstep question: compare the two current roots, then compare left with left and right with right.
Lockstep DFS keeps the two current positions together, so shape and values are checked at the same time.
The blunt approach is serialize-and-compare: turn each tree into a preorder list with explicit null markers, then compare the two lists. That works because null markers preserve shape, but it spends O(n + m) extra space building two full representations before the comparison is finished. The problem statement gives two binary-tree roots, so we can compare those roots directly instead.
A recursive DFS is a natural fit for trees: answer the question at this pair of nodes, then trust the same question on the paired children. Python's boolean operators also short-circuit, so the second subtree check is skipped if the first already proves failure (Python docs: boolean operations).
def isSameTree(p, q):
if not p and not q:
return True # both empty: same here
if not p or not q:
return False # one empty: shapes differ
if p.val != q.val:
return False # roots differ
return (isSameTree(p.left, q.left) and
isSameTree(p.right, q.right)) # paired children
The order matters. Empty-vs-empty is success. Empty-vs-node is failure. Two nodes with different values are failure. Only after those checks do the child pairs get a vote.
Symmetric Tree: is a tree a mirror of itself?
Before opening the reveal: what should the paired recursive calls compare? Say the two pairs out loud.
Use the same lockstep shape, but compare mirror pairs. The root's left subtree must match the root's right subtree. Inside that helper, values match, then left.left pairs with right.right, and left.right pairs with right.left. Same invariant; different pairing rule.
The helper still carries two nodes; only the pairing rule changes from same-side to mirror-side.
| Approach | Time | Space |
|---|---|---|
| Serialize both trees first | O(n + m) | O(n + m) |
| Lockstep DFS comparison | O(n + m) | O(h) |
Worst-case time is still linear because matching trees must be fully checked. The win is cleaner reasoning, early failure on the first mismatch, and only the recursion stack instead of two stored traversals. Here h is the height of the recursion stack.
1. Which line best states this pattern?
2. Spot the bug in this base case:
if not p or not q:
return True
3. What should two null children return?
4. Which task reuses lockstep comparison?
Solve Same Tree tonight, logging it in your Notion tracker with the cycle — predict → attempt → compare → encode:
Watch NeetCode — Same Tree after your attempt, as the compare step. Find the exact moment where his base-case reasoning matches or differs from yours.