Use this composition when one complete rooted tree must appear inside another: candidate roots may occur anywhere, but a candidate succeeds only if every value and missing-child position matches.
Keep true
is_subtree searches every reachable candidate root until one same call succeeds; same(first, second) returns true exactly when the two rooted trees have equal values and recursively identical left and right topology.
Reuse it
Separate locate from verify: DFS locates candidate roots, then a stricter recursive predicate proves complete structure; the same composition applies to tree patterns, AST fragments, and directory subtrees.
Read it this way: Call is_subtree(main3, sub4); same compares roots 3 and 4 before any child search. Step through the frames to watch the state change. The last frame shows the answer or the stopping condition.
Pattern: DFS plus Same Tree.
Simple idea: At each node, check whether the trees are the same from that point. If not,
search the left and right subtrees.
def is_subtree(root: TreeNode | None, subroot: TreeNode | None) -> bool: def same(first: TreeNode | None, second: TreeNode | None) -> bool: if first is None or second is None: return first is second return ( first.val == second.val and same(first.left, second.left) and same(first.right, second.right) ) if subroot is None: return True if root is None: return False return ( same(root, subroot) or is_subtree(root.left, subroot) or is_subtree(root.right, subroot) )
Cost:O(mn) time in the worst case and O(h) call-stack space.
The platform supplies TreeNode with val, left, and right; this snippet assumes that definition.