Facebook Pixel

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 kth 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:

  1. Calculate the sum of node values for each level in the tree
  2. Find the kth largest sum among all these level sums
  3. Return this kth 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 kth largest, not the kth 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.

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

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:

  1. 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.

  2. 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.

  3. 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 from arr 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 Evaluator

Example 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]
  • 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]
  • Node 9: t = 8 + 9 = 17
    • Add child: q = [2, 1, 3]
  • 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]
  • 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 most O(n) nodes in the worst case (when the tree is a complete binary tree, the last level can contain up to n/2 nodes)
  • The array arr stores the sum for each level, which in the worst case (skewed tree) can be O(n) levels
  • The nlargest function internally uses a heap of size k, which is at most O(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]
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What data structure does Breadth-first search typically uses to store intermediate states?


Recommended Readings

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

Load More