Taro Logo

Find the Level of Tree with Minimum Sum

Medium
Asked by:
Profile picture
25 views
Topics:
Trees

Given the root of a binary tree, find the lowest level x such that the sum of all the node values at the level is minimum.

Return the level x (0-indexed).

Example 1:

Input: root = [1,7,0,7,-8,null,null]
Output: 2
Explanation: 
Level 1 sum = 7
Level 2 sum = 7 + (-8) = -1
So level 2 has the minimum sum.

Example 2:

Input: root = [989,null,10250,98693,-89388,null,null,null,-32127]
Output: 1

Constraints:

  • The number of nodes in the tree is in the range [1, 104].
  • -105 <= Node.val <= 105

Solution


Clarifying Questions

When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:

  1. Can the node values in the binary tree be negative, zero, or only positive?
  2. What should I return if the tree is empty (root is null)?
  3. If multiple levels have the same minimum sum, which level should I return (e.g., the smallest level number)?
  4. What is the maximum depth of the binary tree?
  5. Is the binary tree guaranteed to be a complete binary tree or a balanced binary tree, or can it be any arbitrary binary tree?

Brute Force Solution

Approach

We want to find the 'best' level in a tree, where 'best' means the one with the smallest sum of all its values. A brute force approach means we're going to check every single level individually to figure out which one is the winner.

Here's how the algorithm would work step-by-step:

  1. First, consider the very top level of the tree. Calculate the sum of all the values on that level.
  2. Next, go down to the level below. Calculate the sum of all the values on that level.
  3. Keep doing this, level by level, calculating the sum of all the values on each one.
  4. As you calculate each level's sum, remember the smallest sum you've seen so far, and the level it came from.
  5. Once you've gone through every level in the tree, the level you remembered with the smallest sum is your answer.

Code Implementation

def find_level_with_minimum_sum(root):
    if not root:
        return -1

    queue = [root]
    level = 0
    minimum_sum = float('inf')
    minimum_level = 0

    while queue:
        level_sum = 0
        level_size = len(queue)

        # Iterate through all nodes at the current level
        for _ in range(level_size):
            node = queue.pop(0)
            level_sum += node.val

            if node.left:
                queue.append(node.left)

            if node.right:
                queue.append(node.right)

        # Check if current level's sum is the smallest so far
        if level_sum < minimum_sum:

            minimum_sum = level_sum

            # Update the level with the minimum sum
            minimum_level = level

        level += 1

    return minimum_level

Big(O) Analysis

Time Complexity
O(n) – The algorithm visits each node in the tree exactly once to calculate the sum for each level. Since we are exploring all n nodes of the tree, and the work done at each node (addition to level sum) is constant, the overall time complexity is directly proportional to the number of nodes. Therefore, the time complexity is O(n), where n is the number of nodes in the tree. The level-by-level processing is performed using a queue (implicitly or explicitly) in breadth-first manner, ensuring each node is visited once.
Space Complexity
O(W) – The algorithm iterates through each level of the tree. To calculate the sum of each level, we need to store the nodes at the current level being processed. In the worst-case scenario (a balanced tree), the width of the widest level could be proportional to the total number of nodes, but it could also be significantly smaller. The space required to store nodes at a level is proportional to the maximum width (W) of any level in the tree. Therefore, the auxiliary space used is O(W), where W is the maximum width of any level in the tree.

Optimal Solution

Approach

The task is to find which level of a tree has the smallest total value. We do this by visiting each level one by one and keeping track of the sum of the values at each level.

Here's how the algorithm would work step-by-step:

  1. Start by going through the tree level by level.
  2. For each level, add up all the values of the tree's parts located at that level.
  3. Keep track of the sum for each level and which level it belongs to.
  4. Compare the sums to find the smallest one.
  5. The level that produced the smallest sum is the answer.

Code Implementation

from collections import deque

def find_minimum_level_sum(root):
    if not root:
        return -1

    queue = deque([root])
    minimum_sum = float('inf')
    minimum_level = 0
    current_level = 0

    while queue:
        current_level_size = len(queue)
        current_level_sum = 0

        # Iterate through all nodes on the current level
        for _ in range(current_level_size):
            node = queue.popleft()
            current_level_sum += node.val

            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)

        # Update the minimum sum and level if needed
        if current_level_sum < minimum_sum:
            # Check if the current level sum is smaller
            minimum_sum = current_level_sum
            minimum_level = current_level

        current_level += 1

    return minimum_level

Big(O) Analysis

Time Complexity
O(n) – The algorithm traverses the tree level by level. In the worst-case scenario, the algorithm visits every node in the tree to calculate the sum for each level. If n is the number of nodes in the tree, the algorithm iterates through all n nodes once. Therefore, the time complexity is directly proportional to the number of nodes, resulting in O(n) complexity.
Space Complexity
O(W) – The algorithm traverses the tree level by level. At each level, it calculates the sum of the nodes' values. To do this efficiently, a queue (or similar data structure like a list) is commonly used to store the nodes at the current level. In the worst-case scenario, the queue might need to hold all the nodes at the widest level of the tree. Therefore, the auxiliary space used is proportional to the maximum width (W) of the tree. Thus, the space complexity is O(W).

Edge Cases

Null or empty tree (root is null)
How to Handle:
Return 0 or -1 to indicate an invalid tree or no levels, depending on the requirements.
Tree with only one node (root only)
How to Handle:
Return level 1 as it's the only level and thus has the minimum sum.
Tree with all nodes having negative values.
How to Handle:
The algorithm should correctly identify the level with the *least negative* sum.
Tree with all nodes having zero values.
How to Handle:
The algorithm should return the lowest level number as the minimum in this case.
Tree with extremely large values that can cause integer overflow when summing the nodes on a level.
How to Handle:
Use a data type with a larger range (e.g., long) to prevent integer overflow.
Unbalanced tree (highly skewed to one side).
How to Handle:
BFS approach handles unbalanced trees efficiently as it processes level by level.
Perfectly balanced tree with a large number of nodes.
How to Handle:
BFS approach processes each node once, so the time complexity remains linear O(N).
Very deep tree exceeding stack limit if using recursion.
How to Handle:
Use iterative BFS (Breadth-First Search) instead of recursive DFS (Depth-First Search) to avoid stack overflow.