Before attempting this problem, you should be comfortable with:
A uni-value subtree is one where all nodes have the same value. We can use DFS to check each subtree from the bottom up. For a node to be the root of a uni-value subtree, both its children must be roots of uni-value subtrees, and the node's value must match its children's values (if they exist). Leaf nodes are always uni-value subtrees.
true if the subtree rooted at the current node is a uni-value subtree.null, return true.false.false.true.false (one of the subtrees is not uni-value).class Solution:
def countUnivalSubtrees(self, root: Optional[TreeNode]) -> int:
self.count = 0
def dfs(node):
if node is None:
return True
isLeftUniValue = dfs(node.left)
isRightUniValue = dfs(node.right)
# If both the children form uni-value subtrees, we compare the value of
# chidrens node with the node value.
if isLeftUniValue and isRightUniValue:
if node.left and node.val != node.left.val:
return False
if node.right and node.val != node.right.val:
return False
self.count += 1
return True
# Else if any of the child does not form a uni-value subtree, the subtree
# rooted at node cannot be a uni-value subtree.
return False
dfs(root)
return self.countWhere is the number of nodes in the given binary tree
The previous solution uses a global or instance variable to track the count. We can avoid this by passing a mutable container (like an array or reference) through the recursion. This makes the function more self-contained and easier to test, while keeping the same logic.
null, return true.count[0] and return true.false.0, call DFS on the root, and return count[0].class Solution:
def countUnivalSubtrees(self, root: Optional[TreeNode]) -> int:
def dfs(node, count):
if node is None:
return True
isLeftUniValue = dfs(node.left, count)
isRightUniValue = dfs(node.right, count)
# If both the children form uni-value subtrees, we compare the value of
# chidrens node with the node value.
if isLeftUniValue and isRightUniValue:
if node.left and node.val != node.left.val:
return False
if node.right and node.val != node.right.val:
return False
count[0] += 1
return True
# Else if any of the child does not form a uni-value subtree, the subtree
# rooted at node cannot be a uni-value subtree.
return False
count = [0]
dfs(root, count)
return count[0]Where is the number of nodes in the given binary tree
Using short-circuit evaluation with and can skip processing one subtree entirely, causing missed counts. Both subtrees must be fully traversed to count all uni-value subtrees, even if one returns false.
# Incorrect - if left is false, right subtree is never processed
if dfs(node.left) and dfs(node.right):
# ...
# Correct - process both subtrees before combining results
left = dfs(node.left)
right = dfs(node.right)
if left and right:
# ...Attempting to access a child's value without first checking if the child exists causes a null pointer exception. Always verify the child is not null before comparing values.
# Incorrect - crashes if node.left is None
if node.left.val != node.val:
return False
# Correct - check for null first
if node.left and node.left.val != node.val:
return FalseA common mistake is incrementing the count before validating that the current node's value matches its children. The count should only increase after confirming all uni-value conditions are met.
# Incorrect - increments before checking value match
if left and right:
count += 1
if node.left and node.val != node.left.val:
return False
# Correct - increment only after all checks pass
if left and right:
if node.left and node.val != node.left.val:
return False
if node.right and node.val != node.right.val:
return False
count += 1
return True