2583. Kth Largest Sum in a Binary Tree
Problem Description
You are given the root of a binary tree and a positive integer k
.
In this problem, you need to find the k
th largest level sum in the tree. A level sum is the sum of all node values that are at the same depth (or level) in the tree. Two nodes are considered to be on the same level if they have the same distance from the root node.
For example, in a binary tree:
- The root node is at level 1
- Children of the root are at level 2
- Grandchildren of the root are at level 3
- And so on...
You need to:
- Calculate the sum of node values for each level in the tree
- Find the
k
th largest sum among all these level sums - Return this
k
th largest value
Important Notes:
- The level sums don't need to be distinct (there could be duplicate sums)
- If the tree has fewer than
k
levels, return-1
- The problem asks for the
k
th largest, not thek
th smallest
For instance, if a tree has level sums of [10, 20, 15, 7]
and k = 2
, you would return 15
(the second largest sum).
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 (specifically, a connected acyclic graph).
Is it a tree?
- Yes: The problem explicitly states we're working with a binary tree.
DFS?
- Not necessarily: While DFS could work, let's consider what the problem asks for. We need to calculate sums for each level of the tree. Level-by-level processing is a key characteristic that suggests BFS might be more natural here.
However, following the flowchart strictly from the tree node leads to DFS. But let's reconsider the problem requirements:
Actually, let me trace through an alternative path that better fits our problem:
Is it a graph?
- Yes: A binary tree is a graph.
Is it a tree?
- No (for this path): While it IS a tree, let's explore other paths since we need level-wise processing.
Is the problem related to directed acyclic graphs?
- No: We're not dealing with topological ordering or DAG-specific properties.
Is the problem related to shortest paths?
- No: We're calculating level sums, not finding paths.
Does the problem involve connectivity?
- No: We're not checking if nodes are connected.
Does the problem have small constraints?
- No: The constraints aren't particularly small, and we need an efficient solution.
BFS?
- Yes: BFS is perfect for level-by-level traversal, which is exactly what we need to calculate the sum of nodes at each level.
Conclusion: The flowchart leads us to BFS (Breadth-First Search) when we recognize that the problem requires level-wise processing of the tree. BFS naturally processes all nodes at the same level before moving to the next level, making it ideal for calculating level sums. After collecting all level sums using BFS, we can sort them and find the kth largest value.
Intuition
The key insight for this problem comes from understanding what we need: the sum of nodes at each level of the tree. When we think about traversing a tree level by level, BFS naturally comes to mind because it processes all nodes at depth d
before moving to depth d+1
.
Think of BFS like filling water in a tree structure - the water spreads horizontally across each level before dropping down to the next level. This is exactly the behavior we want.
Here's how we arrive at the solution approach:
-
Level-wise Processing: We need to group nodes by their levels. BFS inherently does this by using a queue. When we start processing a level, all nodes in the queue belong to the current level.
-
Calculating Level Sums: For each level, we need to sum all node values. With BFS, we can track the queue size at the beginning of each level - this tells us exactly how many nodes belong to the current level. We process exactly that many nodes and accumulate their sum.
-
Finding the kth Largest: Once we have all level sums, finding the kth largest is straightforward - we can either:
- Sort the array and pick the kth element from the end
- Use a heap-based approach to find the kth largest more efficiently
The beauty of this approach is that BFS gives us the level sums in a single traversal of the tree. We visit each node exactly once, making it efficient.
The edge case to consider is when k
is greater than the number of levels in the tree. In this case, we simply return -1
as specified in the problem.
The time complexity is O(n + L log L)
where n
is the number of nodes (for BFS traversal) and L
is the number of levels (for sorting the level sums). The space complexity is O(n)
for the queue in the worst case (when the tree is a complete binary tree, the last level can have up to n/2
nodes).
Learn more about Tree, Breadth-First Search, Binary Tree and Sorting patterns.
Solution Approach
The solution implements BFS traversal with level-wise processing and sorting to find the kth largest level sum. Let's walk through the implementation step by step:
1. Initialize Data Structures:
- Create an empty array
arr
to store the sum of each level - Initialize a deque (double-ended queue)
q
with the root node for BFS traversal
2. BFS Traversal with Level Processing:
while q:
t = 0 # Initialize sum for current level
for _ in range(len(q)): # Process all nodes at current level
The key insight here is using range(len(q))
at the beginning of each level. This captures the exact number of nodes at the current level before we start adding children nodes to the queue.
3. Process Each Node at Current Level:
root = q.popleft() t += root.val if root.left: q.append(root.left) if root.right: q.append(root.right)
For each node at the current level:
- Remove it from the front of the queue
- Add its value to the current level's sum
t
- Add its children (if they exist) to the back of the queue for processing in the next level
4. Store Level Sum:
arr.append(t)
After processing all nodes at the current level, append the total sum to our array.
5. Find the kth Largest:
return -1 if len(arr) < k else nlargest(k, arr)[-1]
This line handles two cases:
- If the tree has fewer than
k
levels (len(arr) < k
), return-1
- Otherwise, use
nlargest(k, arr)
which returns the k largest elements fromarr
in descending order, then take the last element[-1]
which is the kth largest
The nlargest
function from Python's heapq
module efficiently finds the k largest elements using a min-heap of size k, which is more efficient than fully sorting when k is small relative to the number of levels.
Time Complexity: O(n + L log k)
where n is the number of nodes and L is the number of levels
Space Complexity: O(n)
for the queue in worst case plus O(L)
for storing level sums
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 the solution approach.
Consider this binary tree with k = 2
:
5 / \ 8 9 / \ \ 2 1 3 / 4
Step 1: Initialize
arr = []
(to store level sums)q = [5]
(queue starts with root)
Step 2: Process Level 1
- Queue size = 1, so we process 1 node
- Node 5:
t = 0 + 5 = 5
- Add children:
q = [8, 9]
- Add children:
- Level sum = 5,
arr = [5]
Step 3: Process Level 2
- Queue size = 2, so we process 2 nodes
- Node 8:
t = 0 + 8 = 8
- Add children:
q = [9, 2, 1]
- Add children:
- Node 9:
t = 8 + 9 = 17
- Add child:
q = [2, 1, 3]
- Add child:
- Level sum = 17,
arr = [5, 17]
Step 4: Process Level 3
- Queue size = 3, so we process 3 nodes
- Node 2:
t = 0 + 2 = 2
- Add child:
q = [1, 3, 4]
- Add child:
- Node 1:
t = 2 + 1 = 3
- No children to add
- Node 3:
t = 3 + 3 = 6
- No children to add
- Level sum = 6,
arr = [5, 17, 6]
Step 5: Process Level 4
- Queue size = 1, so we process 1 node
- Node 4:
t = 0 + 4 = 4
- No children to add
- Level sum = 4,
arr = [5, 17, 6, 4]
Step 6: Find 2nd Largest
arr = [5, 17, 6, 4]
- Sorted in descending order:
[17, 6, 5, 4]
- 2nd largest = 6
Answer: 6
The algorithm correctly identifies that level 3 (with nodes 2, 1, and 3) has the second-largest sum of 6.
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 heapq import nlargest
10from typing import Optional
11
12class Solution:
13 def kthLargestLevelSum(self, root: Optional[TreeNode], k: int) -> int:
14 # Store the sum of each level
15 level_sums = []
16
17 # Initialize queue for BFS with the root node
18 queue = deque([root])
19
20 # Perform level-order traversal
21 while queue:
22 # Calculate sum for current level
23 current_level_sum = 0
24 level_size = len(queue)
25
26 # Process all nodes at the current level
27 for _ in range(level_size):
28 node = queue.popleft()
29 current_level_sum += node.val
30
31 # Add children to queue for next level
32 if node.left:
33 queue.append(node.left)
34 if node.right:
35 queue.append(node.right)
36
37 # Store the sum of this level
38 level_sums.append(current_level_sum)
39
40 # Check if we have at least k levels
41 if len(level_sums) < k:
42 return -1
43
44 # Find the kth largest sum using heap
45 # nlargest returns k largest elements, take the smallest among them
46 return nlargest(k, level_sums)[-1]
47
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 kth largest sum among all level sums in a binary tree.
19 * Uses BFS to calculate sum for each level, then sorts to find kth largest.
20 *
21 * @param root The root node of the binary tree
22 * @param k The position of the largest sum to find (1-indexed)
23 * @return The kth largest level sum, or -1 if there are fewer than k levels
24 */
25 public long kthLargestLevelSum(TreeNode root, int k) {
26 // List to store the sum of each level
27 List<Long> levelSums = new ArrayList<>();
28
29 // Queue for BFS traversal
30 Deque<TreeNode> queue = new ArrayDeque<>();
31 queue.offer(root);
32
33 // Process tree level by level
34 while (!queue.isEmpty()) {
35 long currentLevelSum = 0;
36 int nodesInCurrentLevel = queue.size();
37
38 // Process all nodes in the current level
39 for (int i = 0; i < nodesInCurrentLevel; i++) {
40 TreeNode currentNode = queue.pollFirst();
41 currentLevelSum += currentNode.val;
42
43 // Add children to queue for next level processing
44 if (currentNode.left != null) {
45 queue.offer(currentNode.left);
46 }
47 if (currentNode.right != null) {
48 queue.offer(currentNode.right);
49 }
50 }
51
52 // Store the sum of current level
53 levelSums.add(currentLevelSum);
54 }
55
56 // Check if we have at least k levels
57 if (levelSums.size() < k) {
58 return -1;
59 }
60
61 // Sort level sums in descending order
62 Collections.sort(levelSums, Collections.reverseOrder());
63
64 // Return the kth largest sum (k-1 index since list is 0-indexed)
65 return levelSums.get(k - 1);
66 }
67}
68
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 long long kthLargestLevelSum(TreeNode* root, int k) {
15 // Store the sum of each level
16 vector<long long> levelSums;
17
18 // Initialize BFS queue with root node
19 queue<TreeNode*> bfsQueue;
20 bfsQueue.push(root);
21
22 // Perform level-order traversal
23 while (!bfsQueue.empty()) {
24 long long currentLevelSum = 0;
25 int currentLevelSize = bfsQueue.size();
26
27 // Process all nodes at the current level
28 for (int i = 0; i < currentLevelSize; ++i) {
29 TreeNode* currentNode = bfsQueue.front();
30 bfsQueue.pop();
31
32 // Add current node's value to level sum
33 currentLevelSum += currentNode->val;
34
35 // Add children to queue for next level processing
36 if (currentNode->left) {
37 bfsQueue.push(currentNode->left);
38 }
39 if (currentNode->right) {
40 bfsQueue.push(currentNode->right);
41 }
42 }
43
44 // Store the sum of current level
45 levelSums.push_back(currentLevelSum);
46 }
47
48 // Check if we have enough levels
49 if (levelSums.size() < k) {
50 return -1;
51 }
52
53 // Sort level sums in descending order
54 sort(levelSums.rbegin(), levelSums.rend());
55
56 // Return the k-th largest level sum (k-1 index due to 0-based indexing)
57 return levelSums[k - 1];
58 }
59};
60
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 kth largest sum among all level sums in a binary tree
17 * @param root - The root node of the binary tree
18 * @param k - The position of the largest sum to find (1-indexed)
19 * @returns The kth largest level sum, or -1 if there are fewer than k levels
20 */
21function kthLargestLevelSum(root: TreeNode | null, k: number): number {
22 // Handle edge case of null root
23 if (!root) {
24 return -1;
25 }
26
27 // Store all level sums
28 const levelSums: number[] = [];
29
30 // Initialize queue for BFS with root node
31 const queue: TreeNode[] = [root];
32
33 // Process tree level by level using BFS
34 while (queue.length > 0) {
35 // Calculate sum for current level
36 let currentLevelSum: number = 0;
37 const currentLevelSize: number = queue.length;
38
39 // Process all nodes in the current level
40 for (let i = 0; i < currentLevelSize; i++) {
41 const currentNode: TreeNode = queue.shift()!;
42 currentLevelSum += currentNode.val;
43
44 // Add child nodes to queue for next level processing
45 if (currentNode.left) {
46 queue.push(currentNode.left);
47 }
48 if (currentNode.right) {
49 queue.push(currentNode.right);
50 }
51 }
52
53 // Store the sum of current level
54 levelSums.push(currentLevelSum);
55 }
56
57 // Check if we have enough levels for kth largest
58 if (levelSums.length < k) {
59 return -1;
60 }
61
62 // Sort level sums in descending order
63 levelSums.sort((a: number, b: number) => b - a);
64
65 // Return kth largest sum (k is 1-indexed)
66 return levelSums[k - 1];
67}
68
Time and Space Complexity
Time Complexity: O(n × log n)
The algorithm performs a level-order traversal (BFS) of the binary tree, which visits each node exactly once, taking O(n)
time where n
is the number of nodes. During traversal, it calculates the sum for each level and stores these sums in the array arr
. After traversal, the nlargest(k, arr)
function is called, which uses a min-heap of size k
internally. This operation takes O(L × log k)
time where L
is the number of levels. In the worst case, L
can be n
(a skewed tree), and k
can be n
as well, making this O(n × log n)
. Since O(n) + O(n × log n) = O(n × log n)
, the overall time complexity is O(n × log n)
.
Space Complexity: O(n)
The space complexity consists of several components:
- The deque
q
for BFS can hold at mostO(n)
nodes in the worst case (when the tree is a complete binary tree, the last level can contain up ton/2
nodes) - The array
arr
stores the sum for each level, which in the worst case (skewed tree) can beO(n)
levels - The
nlargest
function internally uses a heap of sizek
, which is at mostO(n)
Therefore, the total space complexity is O(n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Misunderstanding the k-th Largest Requirement
Pitfall: A common mistake is confusing "k-th largest" with "k-th smallest" or incorrectly handling the indexing. Developers might sort the array in ascending order and access arr[k-1]
or sort in descending order but use the wrong index.
Example of incorrect approach:
# WRONG: This finds k-th smallest, not k-th largest
level_sums.sort()
return level_sums[k-1] if k <= len(level_sums) else -1
# WRONG: Off-by-one error with descending sort
level_sums.sort(reverse=True)
return level_sums[k] # Should be level_sums[k-1]
Solution:
# Correct approach 1: Sort descending and use k-1 index
level_sums.sort(reverse=True)
return level_sums[k-1] if k <= len(level_sums) else -1
# Correct approach 2: Use nlargest and take the last element
from heapq import nlargest
return nlargest(k, level_sums)[-1] if k <= len(level_sums) else -1
2. Incorrect Level Boundary Detection in BFS
Pitfall: Failing to properly track where one level ends and the next begins. This happens when developers don't capture the queue size at the start of each level iteration.
Example of incorrect approach:
# WRONG: This doesn't properly separate levels while queue: node = queue.popleft() current_level_sum += node.val # This mixes nodes from different levels! if node.left: queue.append(node.left) if node.right: queue.append(node.right)
Solution:
# Correct: Capture level size before processing
while queue:
current_level_sum = 0
level_size = len(queue) # Capture size BEFORE adding children
for _ in range(level_size): # Process exactly this many nodes
node = queue.popleft()
current_level_sum += node.val
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
level_sums.append(current_level_sum)
3. Not Handling Edge Cases Properly
Pitfall: Forgetting to check if the tree has fewer levels than k, or not handling the case where the root is None.
Example of incorrect approach:
# WRONG: Doesn't check if root is None
def kthLargestLevelSum(self, root: Optional[TreeNode], k: int) -> int:
queue = deque([root]) # Will add None to queue if root is None
# ... rest of code
# WRONG: Returns wrong value when tree has fewer than k levels
return sorted(level_sums, reverse=True)[k-1] # IndexError if len(level_sums) < k
Solution:
# Correct: Handle None root
if not root:
return -1
# Correct: Check level count before accessing
if len(level_sums) < k:
return -1
return nlargest(k, level_sums)[-1]
What data structure does Breadth-first search typically uses to store intermediate states?
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 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
Binary Tree Min Depth Prereq BFS on Tree problems bfs_intro Given a binary tree find the depth of the shallowest leaf node https assets algo monster binary_tree_min_depth png Explanation We can solve this problem with either DFS or BFS With DFS we traverse the whole tree looking for leaf nodes and record and update the minimum depth as we go With BFS though since we search level by level we are guaranteed to find the shallowest leaf node
Want a Structured Path to Master System Design Too? Don’t Miss This!