Subtree of Another Tree
You are given the roots of two binary trees, root and subRoot. Return true if some node of root is the top of a subtree that is identical to subRoot, and false otherwise.
A subtree of a node consists of that node and all of its descendants, so a match must agree on every value and every child position all the way down to the leaves; root itself also counts as one of its own subtrees.
Both trees are written in level order with null for missing children.
Example 1
subRoot.Example 2
root also has the 5 below its 7, so its subtree is not an exact copy of subRoot.Example 3
subRoot.Constraints
1 <= nodes inroot<= 20001 <= nodes insubRoot<= 1000-104 <= Node.val <= 104
Pattern Path · Trees: DFS · problem 86 of 169
root should you try as the top of a match?root; if the tree starting there is the same as subRoot, return true. Otherwise search the left and right subtrees.Start simple
This problem's natural solution already tries each node as a candidate: O(m · n) time for m and n nodes. A more naive variant serializes every subtree of root separately and compares strings, which costs even more time and memory.
The key idea
Break the task into two recursive questions.
Same tree? same(a, b) is true when both are empty, or when both exist, have equal values, and same(a.left, b.left) and same(a.right, b.right) hold. It stops at the first difference.
Where could it start? A matching subtree must begin at some node of root. So isSubtree(node) is true if same(node, subRoot), or if the match is somewhere in the left or right subtree. An empty node cannot contain a non-empty subRoot.
Because same compares down to the leaves, a node whose subtree merely contains the pattern plus extra children is correctly rejected.
In the worst case same runs for up to n nodes at each of the m nodes of root, so the time is O(m · n), but it usually fails within a few steps. For a guaranteed linear bound you can serialize both trees with explicit null markers and run a string search (KMP), or compare hashes of subtrees.
Complexity
- Time:
O(m · n) worst case - Space:
O(h) recursion depth
Python
class Solution:
def isSubtree(self, root, subRoot):
def same(a, b):
if a is None or b is None:
return a is b
return a.val == b.val and same(a.left, b.left) and same(a.right, b.right)
if root is None:
return False
if same(root, subRoot):
return True
return self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)
JavaScript
var isSubtree = function(root, subRoot) {
const same = (a, b) => {
if (!a || !b) return a === b;
return a.val === b.val && same(a.left, b.left) && same(a.right, b.right);
};
if (!root) return false;
if (same(root, subRoot)) return true;
return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
};
What the interviewer is checking
It tests whether you can compose two recursive functions cleanly, and whether you can discuss the worst case and a linear-time improvement via serialization or hashing.
Mistakes to avoid
- Accepting a node whose subtree contains
subRootplus extra descendants (comparing only the top part). - Serializing without null markers or value separators, so different trees produce the same string (e.g. 12 vs 1,2).
- Only trying to match at nodes whose value equals
subRoot's root but forgetting to keep searching after a failed match.
Follow-ups to expect
- Can you make it linear? (Serialize with nulls, then KMP search.)
- What if the trees are huge and compared often? (Merkle-style subtree hashes.)
- Count how many times subRoot occurs. (Keep counting instead of returning early.)
In real software
Finding a repeated component inside a larger structure, such as a code fragment in an abstract syntax tree for clone detection, or an element pattern in a DOM, is this problem at scale.