Skip to main content

Subtree of Another Tree

How to search for a real subtree by comparing shape and values, not just roots that seem to match.

Given two binary trees root and subRoot, return true if there is a node in root whose subtree is exactly equal to subRoot.

Equal here means:

  • same values
  • same structure

Example:

Input:
  root = [3,4,5,1,2]
  subRoot = [4,1,2]

Output:
  true

What to notice before coding

Common mistakes

Step 1 - Understand what "is a subtree" really asks for

A common reading is:

  • "is there a node with the same value?"

That is not the question.

The real point is:

  • starting from some node in root
  • the whole structure must match subRoot

Step 2 - Write a very direct baseline

One possible baseline is:

  • serialize subRoot
  • serialize every subtree of root
  • compare the strings

It works if you include null markers.

But it repeats too much serialization work.

Step 3 - Split the two questions

At any node in root, there are really two different questions:

  • is this tree exactly equal to subRoot?
  • if not here, is the answer on the left or on the right?

Once you separate those, the recursion gets clean.

Step 4 - Create a structural equality helper

The equality function must check:

  • both null at the same time
  • current value
  • left with left
  • right with right

After that, the main search only needs to try that comparison at each candidate.

The interactive editor needs JavaScript. You can still read the prompt and copy the starter code below.

Starter code

export function isSubtree(root, subRoot) {
  // root and subRoot are objects like { val: number, left: ..., right: ... } or null
  // your solution here
  return false
}
solution.ts
Stuck? Hints available.

Haven't solved it yet?

Viewing the solution now may reduce learning. It's worth trying a bit more.

Open the reference solution

Without JavaScript, the reference solution is shown inline instead of in a dialog.

Solution

Final complexity

Time: O(n * m)

Space: O(h)

Solution 1 - Serialize every candidate and compare

Good baseline because it makes the structure requirement visible.

function serialize(node): string {
  if (node === null) {
    return "#"
  }

  return `${node.val},${serialize(node.left)},${serialize(node.right)}`
}

export function isSubtree(root, subRoot) {
  if (subRoot === null) {
    return true
  }

  const target = serialize(subRoot)
  const candidates: string[] = []

  function collect(node) {
    if (node === null) {
      return
    }

    candidates.push(serialize(node))
    collect(node.left)
    collect(node.right)
  }

  collect(root)

  return candidates.includes(target)
}

It works.

But it reserializes many full subtrees for no good reason.

Now each node in root only becomes a real candidate when the full comparison makes sense.

function isSameTree(a, b) {
  if (a === null && b === null) {
    return true
  }

  if (a === null || b === null) {
    return false
  }

  return (
    a.val === b.val &&
    isSameTree(a.left, b.left) &&
    isSameTree(a.right, b.right)
  )
}

export function isSubtree(root, subRoot) {
  if (subRoot === null) {
    return true
  }

  if (root === null) {
    return false
  }

  if (isSameTree(root, subRoot)) {
    return true
  }

  return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot)
}

The strong insight here is that the search is about candidates, but confirmation is always structural.

What to say in the interview

A strong short explanation would be:

I split the problem into two functions. isSameTree answers whether two trees are exactly equal in values and structure. isSubtree walks through the bigger tree looking for a place where that full comparison passes. That avoids treating a matching value as if it already proved the subtree.

That shows that you:

  • understood the difference between a local value match and structural equality
  • decomposed the problem into two clear responsibilities
  • explained the recursion without overdoing it

When this pattern shows up again

This pattern comes back when you need to:

  • compare recursive structures
  • distinguish a local candidate from a global confirmation
  • use a helper for tree or list equality
  • recognize when “looks similar” still proves nothing

The point is not memorizing isSubtree.

The point is learning how to separate search from structural confirmation.

Next challenge Kth Smallest Element in a BST Previous challenge Clone Graph

Related challenges

Related articles