Before attempting this problem, you should be comfortable with:
To find the subtree with the maximum average, we need to know each subtree's sum and node count. A key observation is that a subtree's values depend entirely on its children's values. This makes postorder traversal the natural choice: we process children first, then use their results to compute the parent's values.
For each node, we track three things: the number of nodes in its subtree, the sum of values in its subtree, and the maximum average found so far. By bubbling these values up from leaves to the root, we can compute the average at every node and keep track of the best one.
State to hold three values: nodeCount, valueSum, and maxAverage.null, return a state with all zeros.left.nodeCount + right.nodeCount + 1.left.valueSum + right.valueSum + node.val.maxAverage from the root's state.class Solution:
# for each node in the tree, we will maintain three values
class State:
def __init__(self, nodes, sum_val, max_average):
# count of nodes in the subtree
self.node_count = nodes
# sum of values in the subtree
self.value_sum = sum_val
# max average found in the subtree
self.max_average = max_average
def maximumAverageSubtree(self, root: Optional[TreeNode]) -> float:
return self.max_average(root).max_average
def max_average(self, root):
if root is None:
return self.State(0, 0, 0)
# postorder traversal, solve for both child nodes first.
left = self.max_average(root.left)
right = self.max_average(root.right)
# now find nodeCount, valueSum and maxAverage for current node `root`
node_count = left.node_count + right.node_count + 1
sum_val = left.value_sum + right.value_sum + root.val
max_average = max(
(1.0 * sum_val) / node_count, # average for current node
max(right.max_average, left.max_average) # max average from child nodes
)
return self.State(node_count, sum_val, max_average)Where is the number of nodes in the tree
Computing a subtree's average requires knowing the sum and count of all nodes in that subtree. Preorder traversal visits the parent before children, so you would not have the children's information when processing the parent. Postorder ensures children are processed first.
When computing the average, dividing two integers truncates the decimal part in many languages. Always cast to floating-point before division (e.g., 1.0 * sum / count) to get the correct average value.
When aggregating values from children, you must add the current node's value and count it as well. A subtree rooted at a node includes that node itself, not just its descendants.