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
could also be considered as a subtree of itself.
Example 1:
Input: root = [3,4,5,1,2], subRoot = [4,1,2] Output: true
Example 2:
Input: root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2] Output: false
Constraints:
root
tree is in the range [1, 2000]
.subRoot
tree is in the range [1, 1000]
.-104 <= root.val <= 104
-104 <= subRoot.val <= 104
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We want to see if one tree is contained within another. The brute force way is to check every possible place where the smaller tree *could* be inside the larger one, one by one. We are meticulously exploring every single possibility.
Here's how the algorithm would work step-by-step:
def is_subtree(root_of_larger_tree, root_of_smaller_tree):
if not root_of_smaller_tree:
return True
if not root_of_larger_tree:
return False
def are_identical(node_one, node_two):
if not node_one and not node_two:
return True
if not node_one or not node_two or node_one.val != node_two.val:
return False
return are_identical(node_one.left, node_two.left) and are_identical(node_one.right, node_two.right)
# If trees are identical, return True immediately
if are_identical(root_of_larger_tree, root_of_smaller_tree):
return True
# Check left subtree
if is_subtree(root_of_larger_tree.left, root_of_smaller_tree):
return True
# Check right subtree, if left subtree returned False
if is_subtree(root_of_larger_tree.right, root_of_smaller_tree):
return True
return False
To efficiently check if one tree is a subtree of another, we'll explore the larger tree and compare its nodes. We'll look for nodes in the larger tree that have the same value as the root of the smaller tree, and then perform a more detailed comparison from that point.
Here's how the algorithm would work step-by-step:
def is_subtree(root_tree, sub_tree):
if not sub_tree:
return True
if not root_tree:
return False
def is_identical(node_one, node_two):
if not node_one and not node_two:
return True
if not node_one or not node_two or node_one.val != node_two.val:
return False
return is_identical(node_one.left, node_two.left) and \
is_identical(node_one.right, node_two.right)
def traverse_tree(root_node, sub_node):
# Check for identical subtree at current node
if is_identical(root_node, sub_node):
return True
# Recursively search left and right subtrees
if root_node.left and traverse_tree(root_node.left, sub_node):
return True
if root_node.right and traverse_tree(root_node.right, sub_node):
return True
return False
# Initiate the recursive traversal to find the subtree
return traverse_tree(root_tree, sub_tree)
Case | How to Handle |
---|---|
root is null and subRoot is null | Return true, as an empty tree is considered a subtree of itself. |
root is not null, but subRoot is null | Return true, as an empty tree is considered a subtree of any non-empty tree. |
root is null, but subRoot is not null | Return false, as a non-empty tree cannot be a subtree of an empty tree. |
root and subRoot are single nodes with equal values | Return true, as they are identical trees. |
root and subRoot are single nodes with different values | Return false, as they are not identical trees. |
Large trees with deep recursion depth (potential stack overflow) | Consider iterative approaches using a stack to avoid stack overflow errors or optimize recursive calls. |
root and subRoot have identical structures but very large integer values in the nodes (potential overflow during comparisons) | Use a language feature that supports large integers (e.g., Python's arbitrary precision integers) or a hash of the tree structure to avoid comparisons of large numbers directly. |
root contains many identical subtrees that could potentially match subRoot, but only one actually does | The algorithm should ensure that it correctly identifies the valid subtree and doesn't terminate prematurely on a false positive. |