skip to content

How does a simultaneous recursion over two binary trees decide that they are identical?

level: middleimportance: should knowfreq 58%

answer

  1. walk both trees from the roots together
  2. three cases before you compare keys
  3. where does shape difference actually surface
  4. one position empty, the other occupied
  5. cross the child pairing for mirroring

basics

~20 s

Walk both trees in lockstep from the roots. Both positions empty means agreement; exactly one empty means the shapes differ; otherwise the keys must match and the left pair and right pair must both agree. Cost is O(n) time and O(h) stack.

solid answer

~50 s

The recursion takes a node from each tree and checks three cases in order. If both are empty, this position agrees. If exactly one is empty, the shapes diverge here and the answer is false — that case is where structure, as opposed to content, is actually caught. Otherwise the two keys must be equal, and the check recurses on the two left children as a pair and the two right children as a pair, requiring both. It short-circuits on the first disagreement, costs O(n) time in the worst case where n is the smaller tree's size, and O(h) auxiliary space for the recursion stack. Crucially this is stronger than comparing the trees' key sequences: two trees can hold the same keys, and even produce the same inorder sequence, while having entirely different shapes. Pairing each left child with the *other* tree's right child instead turns the same recursion into a mirror-image check.

code

pseudocode · 9 lines
pseudocode
identical(p, q):
    if p == empty and q == empty:
        return true
    if p == empty or q == empty:
        return false
    if p.key != q.key:
        return false
    return identical(p.left, q.left)
       and identical(p.right, q.right)

go deeper

for a junior

Be ready to write the three base cases in the right order and say which one detects a shape difference. Knowing that identity means same positions, not just same keys, is the core.

for a middle

Explain the cost as O(min(n, m)) time and O(h) stack with short-circuiting, and derive the mirror check by crossing the child pairing rather than writing a second algorithm.

for a senior

Show why a value-sequence checksum is the wrong verification for a restore, and pick the right containment strategy — repeated identity walks versus a marker-based encoding searched linearly.

for a principal

Decide what 'the same tree' has to mean for your system before choosing the check: key set, key order, or exact shape — and accept the verification cost that definition implies.

## Comparing structure, not contents Asking whether two binary trees are *identical* means asking about two things at once: the same shape and the same keys in the same positions. A comparison that only looks at the keys answers a weaker question, and the gap between the two is exactly where restore-verification bugs live. ### The lockstep recursion ``` identical(p, q): if p == empty and q == empty: return true if p == empty or q == empty: return false if p.key != q.key: return false return identical(p.left, q.left) and identical(p.right, q.right) ``` The **order of the base cases matters**. The both-empty case must come first, because it is the only agreement terminal. The exactly-one-empty case is the structural check: it fires when one tree has a child where the other has nothing, which is the only way shape difference can show up locally. Only after both positions are known to be occupied is comparing keys meaningful. Time is O(min(n, m)) — the walk stops as soon as one side runs out or a mismatch appears, so it never visits more nodes than the smaller tree holds. Auxiliary space is O(h) for the call stack, which is O(n) in the degenerate case; an explicit stack of node pairs gives the same traversal iteratively when depth is a concern. Short-circuiting matters in practice: a mismatch near the root ends the comparison after a handful of comparisons, while two identical million-node trees genuinely cost a full traversal. ### Why key-sequence comparison is not enough Suppose a service snapshots an in-memory tree, restores it elsewhere, and verifies the restore by comparing a checksum of the two trees' inorder key sequences. That check passes for a restore that rebuilt a *balanced* tree from the same keys — the key multiset is identical and, for a search tree, so is the inorder sequence, because inorder of any valid search tree over a key set is just those keys sorted. The shapes are completely different. If the shape is meaningless (a pure lookup index) that is fine. If the shape carries meaning — evaluation order, per-node metadata, a path used in an audit record — the verification passed on a restore that lost information. The structural comparison catches it because it walks positions, not values. The general lesson: value-order agreement is a *necessary* consequence of identity, never a *sufficient* witness of it. ### The mirror variant A tree is symmetric when its left subtree is the mirror image of its right. That is the same recursion with the child pairing crossed: ``` mirror(p, q): ... same three base cases ... return mirror(p.left, q.right) and mirror(p.right, q.left) ``` and symmetry of a single tree is `mirror(root.left, root.right)`. Note what does **not** work: comparing a tree's inorder sequence with its reverse. Reversal agreement is necessary but not sufficient, for exactly the reason above — it constrains the values, not the positions. ### Containment: is one tree a subtree of another? The direct method runs the identity check at every host node whose key matches the candidate's root, giving O(n·m) in the worst case — a host that is a long chain of one repeated key and a candidate that agrees for m-1 levels before failing is the shape that realises it. The faster method serialises both trees with explicit empty-child markers and asks whether the candidate's encoding appears as a contiguous block of the host's, which a linear-time string matcher such as KMP answers in O(n+m). Two conditions make that sound: the markers must be present, so that the encoding determines the shape uniquely, and the tokens must be delimited, or the key 2 will appear to match inside the key 12 and manufacture a false hit. ### When comparisons repeat If the same trees are compared many times, hash each subtree bottom-up as a function of its key and its two children's hashes. Two subtrees are then compared in O(1) after an O(n) preprocessing pass, which is what makes repeated diffing of large trees affordable. The tradeoff is the usual one for fingerprinting: equal hashes are strong evidence, not proof, so a collision-sensitive use should confirm a hash match with a real structural walk.

  • Two trees hold the same keys and produce the same inorder sequence. Does that make them identical?
    No. Inorder constrains the values and their relative order, not the positions: for search trees over the same key set the inorder sequence is just those keys sorted, so a balanced tree and a degenerate chain over the same keys agree on it completely. Only a position-by-position walk, or an unambiguous shape-carrying encoding, settles identity.
  • How would you check whether one tree occurs as a subtree of another, and what does it cost?
    Naively, run the identity check at every host node whose key matches the candidate root: O(n·m) worst case, realised when keys repeat and matches fail deep. Better, serialise both trees with empty-child markers and delimiters and search for the candidate's encoding inside the host's with a linear-time matcher, giving O(n+m). Without markers the encoding does not determine the shape and the search reports false hits.
  • How do you compare the same large trees repeatedly without paying O(n) every time?
    Precompute a bottom-up fingerprint per subtree from its key and its children's fingerprints, in one O(n) pass. Subsequent comparisons are O(1) lookups, and unchanged subtrees keep their fingerprint across edits along untouched paths. Because equal fingerprints are strong evidence rather than proof, confirm a match with a real structural walk wherever a false positive would be costly.

saying these in an interview costs you the question

  • Concludes identity from matching key sets
  • Trusts a checksum of the inorder sequence as proof
  • Compares keys before handling the empty cases
  • Checks only that both trees have equal height or size
  • Thinks the mirror check needs a separate traversal

context