Two trees are leaf-similar if their leaf nodes, read from left to right, form the same sequence. We can collect the leaf values from each tree using a depth-first traversal. A node is a leaf if it has no children. By traversing left before right, we naturally encounter leaves in left-to-right order.
dfs that traverses a tree and appends leaf values to a list.null, return immediately.# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def leafSimilar(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool:
def dfs(root, leaf):
if not root:
return
if not root.left and not root.right:
leaf.append(root.val)
return
dfs(root.left, leaf)
dfs(root.right, leaf)
leaf1, leaf2 = [], []
dfs(root1, leaf1)
dfs(root2, leaf2)
return leaf1 == leaf2Where and are the number of nodes in the given trees.
Instead of storing both leaf sequences and comparing at the end, we can collect leaves from the first tree and then verify them against the second tree on the fly. By traversing the second tree in reverse order (right to left) and using a stack, we can pop leaves one by one and compare them immediately. This saves space when one tree has significantly fewer leaves than expected.
false on mismatch or if the stack is empty.true only if all leaves matched and both trees had the same number of leaves.# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def leafSimilar(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool:
def dfs(root, leaf):
if not root:
return
if not root.left and not root.right:
leaf.append(root.val)
return
dfs(root.left, leaf)
dfs(root.right, leaf)
leaf1 = []
dfs(root1, leaf1)
def dfs1(root, leaf):
if not root:
return True
if not root.left and not root.right:
if not leaf:
return False
return leaf.pop() == root.val
return dfs1(root.right, leaf) and dfs1(root.left, leaf)
return dfs1(root2, leaf1) and not leaf1Where and are the number of nodes in the given trees.
Rather than collecting all leaves first, we can compare leaves one at a time using two parallel iterative traversals. Each tree maintains its own stack. We advance each stack until we find the next leaf, compare the two leaves, and continue. This approach can exit early if a mismatch is found without traversing the entire trees.
getPathLeaf that pops nodes from a stack until a leaf is found, pushing children along the way.false.true only if both stacks are empty (both trees exhausted their leaves together).# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def leafSimilar(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool:
def getPathLeaf(stack):
while stack:
node = stack.pop()
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
if not node.left and not node.right:
return node.val
stack1, stack2 = [root1], [root2]
while stack1 and stack2:
if getPathLeaf(stack1) != getPathLeaf(stack2):
return False
return not stack1 and not stack2Where and are the number of nodes in the given trees.
A common mistake is to collect all node values during traversal instead of only the leaf nodes. Remember that a leaf is specifically a node with no left and no right child. Including internal nodes in your comparison will produce incorrect results.
The problem requires leaves to match in left-to-right order. If you traverse right subtrees before left subtrees, you will collect leaves in the wrong sequence. Always process the left child before the right child in your DFS traversal.