Recursive Tree Comparison
Intuition
The straightforward approach is to visit every node in the main tree and check whether the subtree rooted at that node is identical to subRoot. We reuse the "same tree" check as a helper. For each node in root, if it matches subRoot exactly (same structure and values), we return true. Otherwise, we recursively check the left and right subtrees. This approach is simple to implement and builds on the same-tree problem.
Algorithm
- If root is null, return false (no subtree can match).
- If the tree rooted at root is the same as subRoot (using the isSameTree helper), return true.
- Recursively check if subRoot is a subtree of root.left OR root.right.
- The isSameTree helper checks: both null returns true, one null returns false, different values returns false, and recursively compares left and right children.
O(m * n) where m is the size of root and n is the size of subRootSpaceO(m) for the recursion stack in the worst caseCode (C++ · Java · Python · Go)
class Solution {
public:
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if (root == nullptr) return false;
if (isSameTree(root, subRoot)) return true;
return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}
private:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (p == nullptr && q == nullptr) return true;
if (p == nullptr || q == nullptr) return false;
if (p->val != q->val) return false;
return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
};class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if (root == null) return false;
if (isSameTree(root, subRoot)) return true;
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);
}
}def isSubtree(root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool:
def is_same(p, q):
if not p and not q:
return True
if not p or not q:
return False
if p.val != q.val:
return False
return is_same(p.left, q.left) and is_same(p.right, q.right)
if not root:
return False
if is_same(root, subRoot):
return True
return isSubtree(root.left, subRoot) or isSubtree(root.right, subRoot)func isSubtree(root *TreeNode, subRoot *TreeNode) bool {
if root == nil {
return false
}
if isSameTree(root, subRoot) {
return true
}
return isSubtree(root.Left, subRoot) || isSubtree(root.Right, subRoot)
}
func isSameTree(p *TreeNode, q *TreeNode) bool {
if p == nil && q == nil {
return true
}
if p == nil || q == nil {
return false
}
if p.Val != q.Val {
return false
}
return isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right)
}