Subtree of Another Tree
Problem Description
Given the roots of two binary trees root and subRoot, return true if there is a subtree of root with the same structure and node values of subRoot, and false otherwise.
A subtree of a binary tree tree is a tree that consists of a node in tree and all of this node’s descendants. The tree tree can also be considered as a subtree of itself.
Examples
Example 1:Input: root = [3,4,5,1,2], subRoot = [4,1,2] Output: true
Input: root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2] Output: false Explanation: The subtree at node 4 includes node 0, which does not match subRoot.
Constraints
- The number of nodes in the
roottree is in the range[1, 2000]. - The number of nodes in the
subRoottree is in the range[1, 1000]. -10⁴ ≤ root.val ≤ 10⁴-10⁴ ≤ subRoot.val ≤ 10⁴
Checking for Identical Trees at Every Candidate Node
A tree subRoot is a subtree of root if we can find a node in root such that the tree rooted at that node is identical to subRoot.
This requires a two-level recursion:
- Traverse the
roottree. For every node encountered, we check if the tree starting at this node is identical tosubRoot(reusing the logic from the “Same Tree” problem). - If the check succeeds, we return true. If it fails, we recursively check the left and right children of
rootto see ifsubRootmatches further down.
Solution 1: Double Recursion (DFS)
Check if the current root matches subRoot using a helper function. If not, recurse on root.left and root.right.
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if (root == null) return false; // subRoot cannot be a subtree of null
// if they match at this level, we are done
if (isSameTree(root, subRoot)) return true;
// search left and right subtrees
return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
}
private boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) return true;
if (p == null || q == null) return false;
if (p.val != q.val) return false;
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}class Solution:
def isSubtree(self, root: TreeNode, subRoot: TreeNode) -> bool:
if not root:
return False # subRoot cannot be a subtree of null
# if they match at this level, we are done
if self.isSameTree(root, subRoot):
return True
# search left and right subtrees
return self.isSubtree(root.left, subRoot) or self.isSubtree(
root.right, subRoot
)
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
if not p and not q:
return True
if not p or not q:
return False
if p.val != q.val:
return False
return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)class Solution {
private:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (!p && !q) return true;
if (!p || !q) return false;
if (p->val != q->val) return false;
return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
public:
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if (!root) return false; // subRoot cannot be a subtree of null
// if they match at this level, we are done
if (isSameTree(root, subRoot)) return true;
// search left and right subtrees
return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}
};Complexity Analysis:
- Time Complexity: O(s * t) in the worst case, where s is the number of nodes in
rootand t is the number of nodes insubRoot. For each of the s nodes, we might perform a comparison that takes up to t steps. - Space Complexity: O(h_s) where h_s is the height of the
roottree, representing the recursive call stack depth.
Where it breaks: The worst-case time complexity is O(s * t) when there are many nodes in root that have the same value as the root of subRoot. To optimize to O(s + t), we can serialize both trees into strings and use string matching algorithms (like KMP), though this is significantly harder to write during an interview.
Common Mistakes
- Returning
truewhenrootis null. Ifrootis null andsubRootis not null,subRootcannot be a subtree. The base case must returnfalse. - Calling
isSubtree(root.left, subRoot.left)instead ofisSubtree(root.left, subRoot). In the outer recursion, you are searching for the entiresubRoottree inside the subtrees ofroot, so the second argument must remainsubRoot. - Failing to check structure matching strictly. A subtree requires that all descendants match. If
roothas extra nodes below the matching structure, it is not a valid subtree match.
Frequently Asked Questions
Can a tree be a subtree of itself?
Yes. By definition, a tree is considered a subtree of itself, which is handled correctly by the isSameTree(root, subRoot) check at the very first call.
Is there a way to solve this in O(s + t) time?
Yes. You can serialize both trees using pre-order traversal (including null markers) into strings, and then check if the serialized subRoot string is a substring of the serialized root string using the KMP or Rabin-Karp algorithm.
What does this problem test in interviews? It tests your ability to write modular recursive code (reusing the Same Tree helper) and navigate nested recursive functions.