{x}
blog image

Maximum Average Subtree

Solution Explanation: Maximum Average Subtree

This problem asks us to find the maximum average value of a subtree within a given binary tree. A subtree is defined as a node and all its descendants. The average of a subtree is its sum of node values divided by the number of nodes.

Approach:

The most efficient way to solve this problem is using Depth-First Search (DFS) recursively. The idea is to traverse the tree, calculating the sum and count of nodes for each subtree encountered. We keep track of the maximum average found so far.

Algorithm:

  1. Recursive Function dfs(node): This function takes a tree node as input and returns a pair: [sum, count].

  2. Base Case: If node is null (empty subtree), return [0, 0].

  3. Recursive Step:

    • Recursively call dfs() on the left and right subtrees to get their [sum, count] pairs.
    • Calculate the sum of the current subtree: node.val + left_sum + right_sum.
    • Calculate the count of nodes in the current subtree: 1 + left_count + right_count.
    • Calculate the average: sum / count.
    • Update the global maximum average (max_avg) if the current average is greater.
    • Return the [sum, count] pair for the current subtree.
  4. Main Function: Call dfs(root) to start the traversal and return the max_avg.

Time and Space Complexity:

  • Time Complexity: O(N), where N is the number of nodes in the tree. We visit each node exactly once during the DFS traversal.
  • Space Complexity: O(H), where H is the height of the tree. This is due to the recursive call stack. In the worst case (a skewed tree), H could be N, but in a balanced tree, H is log₂(N).

Code Implementation (Python):

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:
        self.max_avg = 0.0
 
        def dfs(node):
            if not node:
                return 0, 0  # sum, count
            left_sum, left_count = dfs(node.left)
            right_sum, right_count = dfs(node.right)
            subtree_sum = node.val + left_sum + right_sum
            subtree_count = 1 + left_count + right_count
            avg = subtree_sum / subtree_count
            self.max_avg = max(self.max_avg, avg)
            return subtree_sum, subtree_count
 
        dfs(root)
        return self.max_avg
 

The implementations in Java, C++, and Go follow the same algorithmic structure, differing only in syntax. The key is the recursive dfs function that efficiently computes the subtree sums and counts while keeping track of the maximum average.