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.
For example:
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
Could you please provide an algorithm and code to solve this problem efficiently? Also, what is the Big O time and space complexity of your solution?
This problem asks us to determine if a binary tree subRoot
is a subtree of another binary tree root
. This means there exists a node in root
such that the tree rooted at that node is identical to subRoot
.
The brute force approach involves traversing the root
tree and, for each node, checking if the subtree rooted at that node is identical to the subRoot
tree. This involves a recursive comparison of the tree structures and node values.
Algorithm:
root
tree using a depth-first search (DFS).root
, call a helper function to check if the subtree rooted at that node is identical to subRoot
.false
. If both trees are exhausted simultaneously, return true
.true
for any node in root
, then subRoot
is a subtree of root
. Otherwise, it is not.Code (Python):
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def isSubtree(root: TreeNode, subRoot: TreeNode) -> bool:
if not subRoot:
return True
if not root:
return False
def is_identical(node1, node2):
if not node1 and not node2:
return True
if not node1 or not node2 or node1.val != node2.val:
return False
return is_identical(node1.left, node2.left) and is_identical(node1.right, node2.right)
def traverse(node):
if not node:
return False
if is_identical(node, subRoot):
return True
return traverse(node.left) or traverse(node.right)
return traverse(root)
Time Complexity: O(m * n), where n is the number of nodes in root
and m is the number of nodes in subRoot
. In the worst case, we might have to compare subRoot
with every node in root
.
Space Complexity: O(h), where h is the height of the root
tree, due to the recursion stack during DFS.
The optimal approach still uses recursion, but combines the tree traversal and comparison logic to reduce the number of redundant comparisons.
Algorithm:
subRoot
is None, it's an empty tree and therefore a subtree of any tree. Return true
.root
is None but subRoot
is not, then subRoot
cannot be a subtree. Return false
.root
and subRoot
are identical using a helper function (same as in the brute force approach).true
.subRoot
is a subtree of either the left or right subtree of root
.Code (Python):
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def isSubtree(root: TreeNode, subRoot: TreeNode) -> bool:
if not subRoot:
return True
if not root:
return False
def is_identical(node1, node2):
if not node1 and not node2:
return True
if not node1 or not node2 or node1.val != node2.val:
return False
return is_identical(node1.left, node2.left) and is_identical(node1.right, node2.right)
if is_identical(root, subRoot):
return True
return isSubtree(root.left, subRoot) or isSubtree(root.right, subRoot)
Time Complexity: O(m * n), where n is the number of nodes in root
and m is the number of nodes in subRoot
. In the worst case, the algorithm might still need to explore all nodes in both trees.
Space Complexity: O(h), where h is the height of the root
tree, due to the recursion stack during DFS.
subRoot
is None
: An empty tree is considered a subtree of any tree, so return True
.root
is None
: If subRoot
is not also None
, then subRoot
cannot be a subtree, so return False
.root
and subRoot
are None
: Return True
.is_identical
helper function handles structural differences.