HARD Lab · Trees · 63

100. Same Tree

Two binary trees are the same when they have identical structure and identical values. Walk both in lockstep with a single recursive DFS — compare the node pair, then the left subtrees, then the right.

EasyDFSTree ComparisonTypeScript

PROBLEM What we're solving

Given the roots of two binary trees p and q, return true only if they are structurally identical and every corresponding node holds the same value. p=[1,2,3], q=[1,2,3]true. p=[1,2], q=[1,null,2]false (the 2 hangs on different sides).

KEY IDEA Two trees are equal ⇔ roots equal and subtrees equal

Insight → "same tree" is recursive. Two trees match iff both roots are absent, OR both roots exist, carry the same value, and their left subtrees match and their right subtrees match. That single sentence is the whole algorithm — a synchronized DFS that advances down both trees together.

RECIPE Compare the pair, then recurse both sides

  • 0 · Both null? If p and q are both null, this branch ends in agreement → return true.
  • 1 · One null? If exactly one is null, the shapes diverge → return false. This is the structural check.
  • 2 · Values differ? If p.val !== q.val, the trees disagree here → return false.
  • 3 · Recurse. Node matches, so demand that left subtrees match and right subtrees match.
Classic confusion → you must compare p.left with q.left and p.right with q.right — never cross them. Same values in a different shape (e.g. a left child vs a right child) is notthe same tree, which is exactly why the "exactly one null" check matters.

COST Complexity & alternatives

Serialize both, compare strings
O(n) + edge cases
Works, but delimiter / null-marker bugs are easy.
Synchronized DFS
O(n)
Visit each node once; O(h) recursion stack.

Space note

Time is O(n) where nis the smaller tree's size (we stop at the first mismatch). Space is O(h) for the call stack — O(log n) balanced, O(n) for a degenerate (linked-list) tree. An iterative version uses an explicit stack/queue of node pairs with the same bounds.

Pattern transfer →the "compare two nodes, then recurse both children" shape powers Symmetric Tree (mirror the recursion: compare left.left with right.right), Subtree of Another Tree (run isSameTree at every node), and Merge Two Binary Trees.

RUN IT Walk both trees in lockstep

step 0 / 8
STARTSynchronized preorder DFS over both trees. Compare each node pair as we go.
visit order
State
1
a.val
1
b.val
verdict
pair matchesmismatch (null / value)root / in progress
slowfast

TYPESCRIPT The solution, annotated

isSameTree.ts
class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
  constructor(val = 0, left: TreeNode | null = null, right: TreeNode | null = null) {
    this.val = val;
    this.left = left;
    this.right = right;
  }
}

function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean {
  // Both empty here -> this branch matches.
  if (p === null && q === null) return true;

  // Exactly one empty -> shapes differ.
  if (p === null || q === null) return false;

  // Values differ at this node -> not the same.
  if (p.val !== q.val) return false;

  // Node matches; both subtrees must match too.
  return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}

Reading it block by block

Base case A — both null. Reaching null on both sides at the same time means the branches ended together. Return true so the parent's && stays alive.
Base case B — exactly one null. If only one side ran out of nodes, the trees have different shapes. Return false immediately. This single line is the entire structural comparison.
Value check. Both nodes exist; if p.val !== q.val they disagree right here, so short-circuit to false without descending.
Recurse both sides.The node matched, so the answer is "do the left subtrees match and do the right subtrees match?" The && short-circuits — the moment any pair fails, recursion unwinds with false.
Complexity → O(n) time (each node visited at most once; we stop early on mismatch), O(h) space for the recursion stack — O(log n) balanced, O(n) worst case.

INTERVIEWFollow-ups they'll ask

  • "Do it iteratively." Push the pair (p, q) onto a stack; pop, apply the same null/value checks, then push (p.left, q.left) and (p.right, q.right).
  • "What about Symmetric Tree?" Same skeleton, but mirror the recursion: compare a.left with b.right and a.right with b.left.
  • "Is t a subtree of s?" Walk s; at each node run isSameTree(node, t). Total O(n·m).
  • "Why not compare in-order traversals?"Different trees can share an in-order sequence; you'd need null markers, which is just a clumsier serialization.

MNEMONIC The one-liner

"Both null pass, one null fail, values must match, then recurse both sides."

TRIGGERS When you see ___ → reach for ___

"are these two trees identical?"synchronized DFS on the pair
compare structure AND valuesboth-null / one-null / val checks
"mirror / symmetric"same skeleton, swap left↔right
"is X a subtree of Y?"isSameTree at every node of Y

SKELETON The reusable shape

skeleton.ts
function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean {
  if (p === null && q === null) return true;   // both empty -> equal
  if (p === null || q === null) return false;  // one empty -> differ
  if (p.val !== q.val) return false;           // value mismatch
  return isSameTree(p.left, q.left)            // recurse left
      && isSameTree(p.right, q.right);         // and right
}

FLASHCARDS Tap to flip

Two trees are the same iff…
roots are both null, OR both exist with equal value and matching left and right subtrees.
tap to flip
1 / 6
Answer to reveal explanations. No penalty for retries.Score: 0 / 7
QUESTION 01
When both p and q are null at the same recursive call, you return:
QUESTION 02
Exactly one of p, q is null. This means:
QUESTION 03
p=[1,2] and q=[1,null,2] (the 2 is a left child vs a right child). Result?
QUESTION 04
Optimal time complexity (n = number of nodes)?
QUESTION 05
Worst-case extra space used by the recursive solution?
QUESTION 06
To adapt this code for Symmetric Tree, you would:
QUESTION 07
Why check p.val !== q.val before recursing?