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:
-
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.
-
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.
-
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.
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:
- Start with the root in a queue
- Process all nodes currently in the queue (these are all at the same level)
- As we process each node, add its value to the current level's sum
- Add the node's children to the queue for the next level
- After processing all nodes at a level, compare its sum with the minimum found so far
- 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:
- Remove it from the front of the queue:
node = q.popleft()
- Add its value to the level sum:
t += node.val
- 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 EvaluatorExample 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
- Update:
- 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
- Update:
- 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:
- The
range(len(q))
ensures we process exactly the nodes at each level, even as we're adding children to the queue - The strict inequality
s > t
means we only update when finding a smaller sum, naturally handling ties by keeping the lower level - 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
Which of the two traversal algorithms (BFS and DFS) can be used to find whether two nodes are connected?
Recommended Readings
Everything About Trees A tree is a type of graph data structure composed of nodes and edges Its main properties are It is acyclic doesn't contain any cycles There exists a path from the root to any node Has N 1 edges where N is the number of nodes in the tree and
https assets algo monster cover_photos dfs svg Depth First Search Prereqs Recursion Review problems recursion_intro Trees problems tree_intro With a solid understanding of recursion under our belts we are now ready to tackle one of the most useful techniques in coding interviews Depth First Search DFS As the name suggests
https assets algo monster cover_photos bfs svg Breadth First Search on Trees Hopefully by this time you've drunk enough DFS Kool Aid to understand its immense power and seen enough visualization to create a call stack in your mind Now let me introduce the companion spell Breadth First Search BFS
Want a Structured Path to Master System Design Too? Don’t Miss This!