Facebook Pixel

3157. Find the Level of Tree with Minimum Sum 🔒

Problem Description

You are given a binary tree with a root node. Each node in the tree has a value. Your task is to find which level of the tree has the minimum sum of all node values at that level.

The tree levels are numbered starting from 1 (the root is at level 1), and each subsequent level increases by 1 based on the distance from the root.

Key requirements:

  • Calculate the sum of node values for each level in the tree
  • Find the level with the smallest sum
  • If multiple levels have the same minimum sum (a tie), return the lowest level number

Example understanding: If you have a tree where:

  • Level 1 (root) has nodes with sum = 10
  • Level 2 has nodes with sum = 5
  • Level 3 has nodes with sum = 5
  • Level 4 has nodes with sum = 8

The answer would be 2, because levels 2 and 3 both have the minimum sum of 5, but level 2 comes first.

The solution uses a level-order traversal (BFS) approach with a queue to process all nodes at each level, calculate their sum, and track which level has the minimum sum encountered so far.

Flowchart Walkthrough

First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:

Is it a graph?

  • Yes: A binary tree is a special type of graph where each node has at most two children and there are no cycles.

Is it a tree?

  • Yes: The problem explicitly states we're working with a binary tree structure with a root node.

DFS

  • Yes: We arrive at DFS as a potential solution pattern for tree problems.

Conclusion: The flowchart suggests using DFS (Depth-First Search) for this tree problem.

However, it's worth noting that while DFS can solve this problem, the actual solution provided uses BFS (Breadth-First Search) instead. This is because:

  1. Level-order traversal is more natural with BFS: Since we need to calculate sums level by level, BFS naturally processes all nodes at the same level together using a queue.

  2. DFS would require additional bookkeeping: With DFS, we'd need to track the level of each node explicitly and accumulate sums in a separate data structure (like a dictionary or array) mapping levels to their sums.

  3. BFS provides immediate level boundaries: The queue-based approach in BFS makes it easy to know when one level ends and the next begins (by processing all nodes currently in the queue).

While the flowchart correctly identifies this as a tree problem suitable for DFS, the specific requirement of finding level-wise sums makes BFS the more efficient and intuitive choice for implementation.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

When we need to find something specific about each level of a tree, we should think about how to process the tree level by level. The key insight is that we need to examine all nodes at the same depth together to calculate their sum.

While DFS can traverse a tree, it naturally goes deep into one branch before exploring others. This means nodes at the same level would be visited at different times during the traversal, making it harder to group them together for sum calculation. We'd need to maintain a separate data structure to track which nodes belong to which level.

BFS, on the other hand, processes nodes in "waves" - all nodes at distance 1 from the root, then all nodes at distance 2, and so on. This natural level-order progression aligns perfectly with our goal of calculating per-level sums.

The approach becomes clear:

  1. Start with the root in a queue
  2. Process all nodes currently in the queue (these are all at the same level)
  3. As we process each node, add its value to the current level's sum
  4. Add the node's children to the queue for the next level
  5. After processing all nodes at a level, compare its sum with the minimum found so far
  6. Keep track of which level number has the minimum sum

The trick to handling ties (multiple levels with the same minimum sum) is simple: only update our answer when we find a strictly smaller sum. This ensures we always keep the lowest level number in case of ties, since we process levels in ascending order.

The use of inf (infinity) as the initial minimum sum ensures that the first level will always become our initial answer, and any subsequent level only replaces it if it has a strictly smaller sum.

Learn more about Tree, Depth-First Search, Breadth-First Search and Binary Tree patterns.

Solution Approach

The solution implements a level-order traversal using BFS with a queue data structure. Let's walk through the implementation step by step:

Data Structure Setup:

  • We use a deque (double-ended queue) initialized with the root node: q = deque([root])
  • Track the answer level in ans = 0
  • Initialize current level counter level = 1 (starting from level 1 for the root)
  • Set initial minimum sum s = inf to ensure any real sum will be smaller

Main BFS Loop: The algorithm processes the tree level by level using a while loop that continues as long as there are nodes in the queue:

while q:
    t = 0  # temporary sum for current level
    for _ in range(len(q)):  # process exactly the nodes at current level

Key Implementation Detail - Level Boundary: The critical insight is using range(len(q)) to process exactly the number of nodes that belong to the current level. When we start processing a level, the queue contains only nodes from that level. As we process them, we add their children (next level nodes) to the queue, but the loop only runs for the original count.

Processing Each Node: For each node at the current level:

  1. Remove it from the front of the queue: node = q.popleft()
  2. Add its value to the level sum: t += node.val
  3. Add its children to the queue for the next level:
    if node.left:
        q.append(node.left)
    if node.right:
        q.append(node.right)

Updating the Minimum: After processing all nodes at a level:

if s > t:  # found a strictly smaller sum
    s = t
    ans = level
level += 1  # move to next level

The condition s > t (not s >= t) ensures that in case of a tie, we keep the lower level number, since we process levels in ascending order.

Time and Space Complexity:

  • Time: O(n) where n is the number of nodes, as we visit each node exactly once
  • Space: O(w) where w is the maximum width of the tree (maximum nodes at any level), which represents the maximum queue size

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a concrete example to illustrate how the BFS solution finds the level with minimum sum.

Consider this binary tree:

        5
       / \
      2   -3
     / \   \
    4   1   6

Initial Setup:

  • Queue: [5] (contains root)
  • ans = 0, level = 1, s = inf

Level 1 Processing:

  • Current queue size: 1 (process 1 node)
  • Level sum t = 0
  • Process node 5:
    • t = 0 + 5 = 5
    • Add children 2 and -3 to queue
  • Queue after level: [2, -3]
  • Compare: s (inf) > t (5)? Yes
    • Update: s = 5, ans = 1
  • Increment: level = 2

Level 2 Processing:

  • Current queue size: 2 (process 2 nodes)
  • Level sum t = 0
  • Process node 2:
    • t = 0 + 2 = 2
    • Add children 4 and 1 to queue
  • Process node -3:
    • t = 2 + (-3) = -1
    • Add child 6 to queue
  • Queue after level: [4, 1, 6]
  • Compare: s (5) > t (-1)? Yes
    • Update: s = -1, ans = 2
  • Increment: level = 3

Level 3 Processing:

  • Current queue size: 3 (process 3 nodes)
  • Level sum t = 0
  • Process node 4:
    • t = 0 + 4 = 4
    • No children to add
  • Process node 1:
    • t = 4 + 1 = 5
    • No children to add
  • Process node 6:
    • t = 5 + 6 = 11
    • No children to add
  • Queue after level: [] (empty)
  • Compare: s (-1) > t (11)? No
    • No update (11 is not smaller than -1)
  • Increment: level = 4

Result: Queue is empty, loop ends. Return ans = 2.

Level 2 has the minimum sum of -1, so the answer is 2.

Key Observations:

  1. The range(len(q)) ensures we process exactly the nodes at each level, even as we're adding children to the queue
  2. The strict inequality s > t means we only update when finding a smaller sum, naturally handling ties by keeping the lower level
  3. Each node is visited exactly once, giving us O(n) time complexity

Solution Implementation

1# Definition for a binary tree node.
2# class TreeNode:
3#     def __init__(self, val=0, left=None, right=None):
4#         self.val = val
5#         self.left = left
6#         self.right = right
7
8from collections import deque
9from typing import Optional
10import math
11
12class Solution:
13    def minimumLevel(self, root: Optional[TreeNode]) -> int:
14        """
15        Find the level with the minimum sum in a binary tree using BFS.
16      
17        Args:
18            root: The root node of the binary tree
19          
20        Returns:
21            The 1-indexed level number with the minimum sum
22        """
23        # Initialize queue for BFS traversal with root node
24        queue = deque([root])
25      
26        # Track the level with minimum sum (1-indexed)
27        min_sum_level = 0
28      
29        # Initialize current level counter and minimum sum tracker
30        current_level = 1
31        min_sum = math.inf
32      
33        # Process tree level by level
34        while queue:
35            # Calculate sum for current level
36            level_sum = 0
37            level_size = len(queue)
38          
39            # Process all nodes at current level
40            for _ in range(level_size):
41                node = queue.popleft()
42                level_sum += node.val
43              
44                # Add children to queue for next level
45                if node.left:
46                    queue.append(node.left)
47                if node.right:
48                    queue.append(node.right)
49          
50            # Update minimum sum and corresponding level if current level has smaller sum
51            if level_sum < min_sum:
52                min_sum = level_sum
53                min_sum_level = current_level
54          
55            # Move to next level
56            current_level += 1
57      
58        return min_sum_level
59
1/**
2 * Definition for a binary tree node.
3 * public class TreeNode {
4 *     int val;
5 *     TreeNode left;
6 *     TreeNode right;
7 *     TreeNode() {}
8 *     TreeNode(int val) { this.val = val; }
9 *     TreeNode(int val, TreeNode left, TreeNode right) {
10 *         this.val = val;
11 *         this.left = left;
12 *         this.right = right;
13 *     }
14 * }
15 */
16class Solution {
17    /**
18     * Finds the level with the minimum sum in a binary tree.
19     * Uses BFS (level-order traversal) to calculate sum at each level.
20     * 
21     * @param root The root node of the binary tree
22     * @return The level number (1-indexed) with the minimum sum
23     */
24    public int minimumLevel(TreeNode root) {
25        // Initialize queue for BFS traversal
26        Deque<TreeNode> queue = new ArrayDeque<>();
27        queue.offer(root);
28      
29        // Track the level with minimum sum and the minimum sum value
30        int minSumLevel = 0;
31        long minSum = Long.MAX_VALUE;
32      
33        // Process tree level by level, starting from level 1
34        for (int currentLevel = 1; !queue.isEmpty(); currentLevel++) {
35            // Calculate sum for current level
36            long currentLevelSum = 0;
37            int nodesInCurrentLevel = queue.size();
38          
39            // Process all nodes at the current level
40            for (int i = 0; i < nodesInCurrentLevel; i++) {
41                TreeNode currentNode = queue.poll();
42                currentLevelSum += currentNode.val;
43              
44                // Add children to queue for next level processing
45                if (currentNode.left != null) {
46                    queue.offer(currentNode.left);
47                }
48                if (currentNode.right != null) {
49                    queue.offer(currentNode.right);
50                }
51            }
52          
53            // Update minimum sum and corresponding level if current level has smaller sum
54            if (currentLevelSum < minSum) {
55                minSum = currentLevelSum;
56                minSumLevel = currentLevel;
57            }
58        }
59      
60        return minSumLevel;
61    }
62}
63
1/**
2 * Definition for a binary tree node.
3 * struct TreeNode {
4 *     int val;
5 *     TreeNode *left;
6 *     TreeNode *right;
7 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
8 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
9 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
10 * };
11 */
12class Solution {
13public:
14    /**
15     * Finds the level with the minimum sum in a binary tree.
16     * Uses BFS (level-order traversal) to calculate sum for each level.
17     * 
18     * @param root The root node of the binary tree
19     * @return The 1-indexed level number with the minimum sum
20     */
21    int minimumLevel(TreeNode* root) {
22        // Initialize queue for BFS traversal with root node
23        std::queue<TreeNode*> bfsQueue;
24        bfsQueue.push(root);
25      
26        // Track the level with minimum sum (1-indexed)
27        int minSumLevel = 0;
28      
29        // Initialize minimum sum to a large value (2^60)
30        long long minSum = 1LL << 60;
31      
32        // Process each level of the tree
33        for (int currentLevel = 1; !bfsQueue.empty(); ++currentLevel) {
34            // Calculate sum for current level
35            long long currentLevelSum = 0;
36          
37            // Get the number of nodes at current level
38            int nodesAtCurrentLevel = bfsQueue.size();
39          
40            // Process all nodes at the current level
41            for (int i = 0; i < nodesAtCurrentLevel; ++i) {
42                // Get and remove the front node from queue
43                TreeNode* currentNode = bfsQueue.front();
44                bfsQueue.pop();
45              
46                // Add current node's value to level sum
47                currentLevelSum += currentNode->val;
48              
49                // Add left child to queue if it exists
50                if (currentNode->left != nullptr) {
51                    bfsQueue.push(currentNode->left);
52                }
53              
54                // Add right child to queue if it exists
55                if (currentNode->right != nullptr) {
56                    bfsQueue.push(currentNode->right);
57                }
58            }
59          
60            // Update minimum sum and corresponding level if current level has smaller sum
61            if (currentLevelSum < minSum) {
62                minSum = currentLevelSum;
63                minSumLevel = currentLevel;
64            }
65        }
66      
67        return minSumLevel;
68    }
69};
70
1/**
2 * Definition for a binary tree node.
3 * class TreeNode {
4 *     val: number
5 *     left: TreeNode | null
6 *     right: TreeNode | null
7 *     constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
8 *         this.val = (val===undefined ? 0 : val)
9 *         this.left = (left===undefined ? null : left)
10 *         this.right = (right===undefined ? null : right)
11 *     }
12 * }
13 */
14
15/**
16 * Finds the level with the minimum sum in a binary tree.
17 * Uses BFS (level-order traversal) to calculate the sum of each level.
18 * @param root - The root node of the binary tree
19 * @returns The 1-indexed level number with the minimum sum
20 */
21function minimumLevel(root: TreeNode | null): number {
22    // Initialize queue with root node for BFS traversal
23    const currentLevelNodes: TreeNode[] = [root];
24  
25    // Track the minimum sum found so far
26    let minSum: number = Infinity;
27  
28    // Track the level with minimum sum
29    let levelWithMinSum: number = 0;
30  
31    // Process each level, starting from level 1
32    for (let currentLevel = 1; currentLevelNodes.length > 0; currentLevel++) {
33        // Queue to store nodes for the next level
34        const nextLevelNodes: TreeNode[] = [];
35      
36        // Calculate sum for current level
37        let currentLevelSum: number = 0;
38      
39        // Process all nodes in the current level
40        for (const node of currentLevelNodes) {
41            // Add current node's value to level sum
42            currentLevelSum += node.val;
43          
44            // Add left child to next level queue if it exists
45            if (node.left) {
46                nextLevelNodes.push(node.left);
47            }
48          
49            // Add right child to next level queue if it exists
50            if (node.right) {
51                nextLevelNodes.push(node.right);
52            }
53        }
54      
55        // Update minimum sum and corresponding level if current level has smaller sum
56        if (currentLevelSum < minSum) {
57            minSum = currentLevelSum;
58            levelWithMinSum = currentLevel;
59        }
60      
61        // Replace current level nodes with next level nodes
62        currentLevelNodes.splice(0, currentLevelNodes.length, ...nextLevelNodes);
63    }
64  
65    return levelWithMinSum;
66}
67

Time and Space Complexity

The time complexity is O(n), where n is the number of nodes in the binary tree. This is because the algorithm uses BFS (Breadth-First Search) to traverse the tree level by level. Each node is visited exactly once - it's added to the queue once when discovered and processed once when dequeued. The operations performed for each node (adding to sum, checking children, appending to queue) are all O(1) operations.

The space complexity is O(n). The dominant factor for space usage is the queue q which stores nodes during the BFS traversal. In the worst case, the queue needs to hold all nodes at the widest level of the tree. For a complete binary tree, the maximum width occurs at the last level, which can contain up to n/2 nodes (approximately half of all nodes in a complete binary tree are at the last level). Therefore, the space complexity is O(n). Additionally, the algorithm uses a constant amount of extra space for variables like ans, level, s, and t, which doesn't affect the overall space complexity.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Incorrect Tie-Breaking Logic

One of the most common mistakes is using <= instead of < when comparing sums:

Incorrect:

if level_sum <= min_sum:  # Wrong! This would return the highest level in case of tie
    min_sum = level_sum
    min_sum_level = current_level

Why it's wrong: Using <= would update the answer every time we encounter the same minimum sum, resulting in returning the highest level with the minimum sum instead of the lowest.

Correct Solution:

if level_sum < min_sum:  # Correct! Only updates for strictly smaller sums
    min_sum = level_sum
    min_sum_level = current_level

2. Processing Nodes from Multiple Levels Together

A critical mistake is not properly isolating nodes by level:

Incorrect:

while queue:
    node = queue.popleft()
    level_sum += node.val  # This mixes nodes from different levels!
    if node.left:
        queue.append(node.left)
    if node.right:
        queue.append(node.right)

Why it's wrong: Without capturing len(queue) at the start of each level, you'll process nodes from different levels together, calculating incorrect level sums.

Correct Solution:

while queue:
    level_size = len(queue)  # Capture current level size first
    level_sum = 0
    for _ in range(level_size):  # Process exactly this many nodes
        node = queue.popleft()
        level_sum += node.val
        # Add children for next level

3. Forgetting to Handle Edge Cases

Not initializing min_sum properly or handling empty trees:

Incorrect:

min_sum = 0  # Wrong! The first level's sum might be negative

Correct Solution:

min_sum = float('inf')  # Ensures any actual sum will be smaller
# Also add null check if needed:
if not root:
    return 0

4. Starting Level Counter at 0

The problem specifies that levels are 1-indexed (root is level 1):

Incorrect:

current_level = 0  # Wrong! Problem states root is at level 1

Correct Solution:

current_level = 1  # Start from 1 as specified

5. Resetting Level Sum in Wrong Place

Forgetting to reset the level sum for each new level:

Incorrect:

level_sum = 0  # If this is outside the while loop
while queue:
    for _ in range(len(queue)):
        level_sum += node.val  # Accumulates across all levels!

Correct Solution:

while queue:
    level_sum = 0  # Reset for each level
    for _ in range(len(queue)):
        level_sum += node.val
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the two traversal algorithms (BFS and DFS) can be used to find whether two nodes are connected?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More