Subtree of Another Tree
DFS over root; at each node, run an exact-match check against subRoot.
3 min read
tree dfs recursion
Problem#
Return true iff subRoot’s tree is a subtree of root’s tree (same structure and values, rooted somewhere in root).
Examples#
root = [3,4,5,1,2], subRoot = [4,1,2]→true.root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]→false.
Constraints#
1 <= nodes in root <= 2000,1 <= nodes in subRoot <= 1000.
Approach#
Walk root. At each node, check whether the subtree there is identical to subRoot. Same-tree check is a structural recursion.
Solution#
struct TreeNode { int val; TreeNode* left; TreeNode* right; };
class Solution { bool same(TreeNode* a, TreeNode* b) { if (!a && !b) return true; if (!a || !b || a->val != b->val) return false; return same(a->left, b->left) && same(a->right, b->right); }public: bool isSubtree(TreeNode* root, TreeNode* subRoot) { if (!root) return false; if (same(root, subRoot)) return true; return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot); }};func isSubtree(root *TreeNode, subRoot *TreeNode) bool { if root == nil { return false } if sameTreeSubtree(root, subRoot) { return true } return isSubtree(root.Left, subRoot) || isSubtree(root.Right, subRoot)}
func sameTreeSubtree(a, b *TreeNode) bool { if a == nil && b == nil { return true } if a == nil || b == nil || a.Val != b.Val { return false } return sameTreeSubtree(a.Left, b.Left) && sameTreeSubtree(a.Right, b.Right)}from typing import Optional
class Solution: def isSubtree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool: if not root: return False if self._same(root, subRoot): return True return self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)
def _same(self, a: Optional[TreeNode], b: Optional[TreeNode]) -> bool: if not a and not b: return True if not a or not b or a.val != b.val: return False return self._same(a.left, b.left) and self._same(a.right, b.right)function isSubtree(root, subRoot) { if (!root) return false; if (sameTree(root, subRoot)) return true; return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);}
function sameTree(a, b) { if (!a && !b) return true; if (!a || !b || a.val !== b.val) return false; return sameTree(a.left, b.left) && sameTree(a.right, b.right);}class Solution { public boolean isSubtree(TreeNode root, TreeNode subRoot) { if (root == null) return false; if (same(root, subRoot)) return true; return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot); }
private boolean same(TreeNode a, TreeNode b) { if (a == null && b == null) return true; if (a == null || b == null || a.val != b.val) return false; return same(a.left, b.left) && same(a.right, b.right); }}function isSubtree(root: TreeNode | null, subRoot: TreeNode | null): boolean { if (!root) return false; if (sameTree(root, subRoot)) return true; return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);}
function sameTree(a: TreeNode | null, b: TreeNode | null): boolean { if (!a && !b) return true; if (!a || !b || a.val !== b.val) return false; return sameTree(a.left, b.left) && sameTree(a.right, b.right);}Editorial#
Naive O(m * n) is fine for the constraints. A faster O(m + n) solution serializes both trees and uses string matching, but it’s overkill here. Short-circuit on the first match.
Complexity#
- Time:
O(m * n). - Space:
O(m + n)recursion.
Concept revision#
Related#