Given the root of a binary tree, each node has an integer value. Find the subtree with the largest average value.
For example, consider the following binary tree:
1
/ \
2 3
/ \
4 5
The subtree rooted at node 2 has nodes with values 2, 4, and 5. The sum of these values is 11, and the number of nodes is 3. Therefore, the average value of this subtree is 11/3 ≈ 3.67.
The subtree rooted at node 1 has nodes with values 1, 2, 3, 4, and 5. The sum of these values is 15, and the number of nodes is 5. Therefore, the average value of this subtree is 15/5 = 3.
In this example, the subtree rooted at node 2 has the largest average value (3.67).
Write a function that takes the root of a binary tree as input and returns the largest average value among all subtrees.
Here is another example:
5
/ \
6 1
In this case, the possible subtrees and their averages are:
The maximum average subtree is the subtree rooted at node 6, with an average of 6.
Given the root of a binary tree, find the maximum average value of any subtree of that tree.
Each node in the tree has a value. The average value of a subtree is defined as the sum of the values of all nodes in the subtree divided by the number of nodes in the subtree.
A brute-force solution would involve traversing every node in the tree and considering it as the root of a subtree. For each subtree, calculate the sum of its nodes and the number of nodes. Then calculate the average. Keep track of the maximum average seen so far.
This approach is inefficient because calculating the sum and count for each subtree involves redundant calculations. For example, when considering a node's grandparent as the root, the sums and counts for the node and its sibling's subtrees are recalculated even though they were already computed when the node and sibling were considered as roots.
A more efficient approach involves a post-order traversal of the tree. During the traversal, for each node, we calculate:
We can then calculate the average value of the subtree rooted at that node. We keep track of the maximum average encountered during the traversal.
This approach avoids redundant calculations by calculating the sum and count for each subtree only once. The post-order traversal ensures that the sums and counts for a node's children are calculated before calculating the sum and count for the node itself.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def maximumAverageSubtree(self, root: TreeNode) -> float:
max_avg = float('-inf')
def postorder(node):
nonlocal max_avg
if not node:
return 0, 0 # (sum, count)
left_sum, left_count = postorder(node.left)
right_sum, right_count = postorder(node.right)
subtree_sum = node.val + left_sum + right_sum
subtree_count = 1 + left_count + right_count
avg = subtree_sum / subtree_count
max_avg = max(max_avg, avg)
return subtree_sum, subtree_count
postorder(root)
return max_avg