Facebook Pixel

1302. Deepest Leaves Sum

Problem Description

You are given the root of a binary tree. Your task is to find the sum of all the leaf nodes that are at the deepest level of the tree.

A leaf node is a node that has no children (no left or right child). The deepest leaves are the leaf nodes that are furthest from the root, meaning they are at the maximum depth in the tree.

For example, if you have a binary tree where:

  • Level 1 (root): has value 1
  • Level 2: has values 2 and 3
  • Level 3: has values 4, 5, 6, and 7 (all are leaves)

The deepest leaves are at level 3 (values 4, 5, 6, 7), so the sum would be 4 + 5 + 6 + 7 = 22.

The solution uses a level-order traversal (BFS) approach with a queue. It processes the tree level by level, calculating the sum of all nodes at each level. Since the traversal goes through all levels sequentially, the last calculated sum will be the sum of the deepest level. When the queue becomes empty after processing the last level, the variable ans contains the sum of the deepest leaves, which is then returned.

The key insight is that by using BFS and recalculating the sum for each level, we don't need to first find the maximum depth and then traverse again - we naturally end up with the sum of the last (deepest) level when the traversal completes.

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.

DFS

  • Conclusion: The flowchart leads us directly to DFS (Depth-First Search) as the recommended approach for tree problems.

Why DFS Works for This Problem

The flowchart correctly identifies DFS as a suitable approach because:

  1. Tree Structure: Binary trees are naturally suited for DFS traversal patterns
  2. Depth Information: DFS can easily track the depth/level of each node as we traverse
  3. Recursive Nature: The problem can be solved by recursively exploring each branch while maintaining depth information

DFS Solution Approach

Using DFS, we can:

  1. Traverse the tree while keeping track of the current depth
  2. Maintain a record of the maximum depth encountered
  3. Sum the values of nodes that are at the maximum depth

The solution shown uses BFS instead, which also works effectively for this problem since we need level-wise information. However, DFS would be equally valid following the flowchart's recommendation - we would recursively traverse the tree, track depths, and accumulate the sum of nodes at the deepest level.

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

Intuition

When we need to find the sum of the deepest leaves, we face two key challenges: identifying which leaves are the deepest, and then summing their values.

The natural thought process is that we need to traverse the entire tree to determine the maximum depth first, then traverse again to sum the values at that depth. However, this would require two passes through the tree.

A more elegant insight emerges: if we process the tree level by level, we can calculate the sum of nodes at each level as we go. By the time we finish traversing the tree, the last sum we calculated will naturally be the sum of the deepest level - because we process levels in order from top to bottom.

Think of it like filling water into containers at different floors of a building. As you go from the top floor down, you keep track of the water amount at each floor. When you reach the bottom (no more floors to visit), the last amount you recorded is automatically from the deepest floor.

This is why the BFS approach with a queue works beautifully here. Each iteration of the outer while loop represents one complete level of the tree. We reset ans = 0 at the start of each level and accumulate all node values at that level. The inner for loop ensures we process exactly the nodes at the current level before moving to the next.

The key realization is that we don't need to know in advance which level is the deepest - by continuously updating our sum for each level, the final value of ans when the queue becomes empty will be our answer. This transforms what could be a complex two-pass algorithm into a simple single-pass solution.

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 (Breadth-First Search) with a queue data structure. Here's how the algorithm works step by step:

Data Structure Used: A deque (double-ended queue) to efficiently add and remove nodes during traversal.

Algorithm Steps:

  1. Initialize the Queue: Start by adding the root node to the queue q = deque([root]).

  2. Level-by-Level Processing: The outer while q: loop continues as long as there are nodes to process. Each iteration of this loop represents one complete level of the tree.

  3. Reset Level Sum: At the start of each level, reset ans = 0. This variable will accumulate the sum of all nodes at the current level.

  4. Process Current Level: The inner loop for _ in range(len(q)): ensures we process exactly the nodes that belong to the current level. The len(q) at the start of the loop captures the number of nodes at this level.

  5. Node Processing: For each node in the current level:

    • Remove it from the front of the queue: node = q.popleft()
    • Add its value to the level sum: ans += node.val
    • Add its children (if they exist) to the queue for the next level:
      if node.left:
          q.append(node.left)
      if node.right:
          q.append(node.right)
  6. Final Result: After the outer loop completes (queue is empty), ans contains the sum of the last level processed, which is the deepest level. Return this value.

Why This Works: The queue ensures nodes are processed level by level from top to bottom. By continuously updating ans for each level and not storing previous level sums, we automatically end up with the sum of the deepest level when traversal completes. The space complexity is O(w) where w is the maximum width of the tree, and time complexity is O(n) where n is the total number of nodes.

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 understand how the BFS solution finds the sum of the deepest leaves.

Consider this binary tree:

        1
       / \
      2   3
     /   / \
    4   5   6

Initial Setup:

  • Queue: [1] (contains root)
  • ans = 0

Level 1 Processing (depth 0):

  • Queue size = 1, so we process 1 node
  • Reset ans = 0
  • Process node 1:
    • ans = 0 + 1 = 1
    • Add children 2 and 3 to queue
  • Queue after level: [2, 3]
  • Current ans = 1

Level 2 Processing (depth 1):

  • Queue size = 2, so we process 2 nodes
  • Reset ans = 0
  • Process node 2:
    • ans = 0 + 2 = 2
    • Add child 4 to queue
  • Process node 3:
    • ans = 2 + 3 = 5
    • Add children 5 and 6 to queue
  • Queue after level: [4, 5, 6]
  • Current ans = 5

Level 3 Processing (depth 2):

  • Queue size = 3, so we process 3 nodes
  • Reset ans = 0
  • Process node 4:
    • ans = 0 + 4 = 4
    • No children to add
  • Process node 5:
    • ans = 4 + 5 = 9
    • No children to add
  • Process node 6:
    • ans = 9 + 6 = 15
    • No children to add
  • Queue after level: [] (empty)
  • Current ans = 15

Result: The queue is now empty, so we exit the outer loop. The final value of ans = 15 is the sum of the deepest leaves (4 + 5 + 6 = 15).

Notice how we kept overwriting ans with each level's sum. The last calculated sum (15) automatically becomes our answer because it represents the deepest level in the tree.

Solution Implementation

1from collections import deque
2from typing import Optional
3
4# Definition for a binary tree node.
5class TreeNode:
6    def __init__(self, val=0, left=None, right=None):
7        self.val = val
8        self.left = left
9        self.right = right
10
11class Solution:
12    def deepestLeavesSum(self, root: Optional[TreeNode]) -> int:
13        """
14        Calculate the sum of values of the deepest leaves in a binary tree.
15        Uses BFS (level-order traversal) to find the deepest level.
16      
17        Args:
18            root: The root node of the binary tree
19          
20        Returns:
21            The sum of all node values at the deepest level
22        """
23        # Initialize queue with root node for BFS traversal
24        queue = deque([root])
25      
26        # Process each level of the tree
27        while queue:
28            # Reset sum for current level
29            current_level_sum = 0
30            # Get the number of nodes at current level
31            level_size = len(queue)
32          
33            # Process all nodes at the current level
34            for _ in range(level_size):
35                # Get next node from queue
36                current_node = queue.popleft()
37                # Add node's value to current level sum
38                current_level_sum += current_node.val
39              
40                # Add children to queue for next level processing
41                if current_node.left:
42                    queue.append(current_node.left)
43                if current_node.right:
44                    queue.append(current_node.right)
45      
46        # Return sum of the last (deepest) level processed
47        return current_level_sum
48
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     * Calculates the sum of values of all nodes at the deepest level of the binary tree.
19     * Uses BFS (level-order traversal) to process the tree level by level.
20     * 
21     * @param root The root node of the binary tree
22     * @return The sum of all leaf nodes at the deepest level
23     */
24    public int deepestLeavesSum(TreeNode root) {
25        // Initialize queue for BFS traversal
26        Deque<TreeNode> queue = new ArrayDeque<>();
27        queue.offer(root);
28      
29        // Variable to store the sum of nodes at current level
30        int sumAtCurrentLevel = 0;
31      
32        // Process tree level by level using BFS
33        while (!queue.isEmpty()) {
34            // Reset sum for the new level
35            sumAtCurrentLevel = 0;
36          
37            // Get the number of nodes at current level
38            int nodesAtCurrentLevel = queue.size();
39          
40            // Process all nodes at current level
41            for (int i = 0; i < nodesAtCurrentLevel; i++) {
42                // Remove and process current node
43                TreeNode currentNode = queue.poll();
44                sumAtCurrentLevel += currentNode.val;
45              
46                // Add left child to queue for next level processing
47                if (currentNode.left != null) {
48                    queue.offer(currentNode.left);
49                }
50              
51                // Add right child to queue for next level processing
52                if (currentNode.right != null) {
53                    queue.offer(currentNode.right);
54                }
55            }
56        }
57      
58        // Return sum of the last (deepest) level processed
59        return sumAtCurrentLevel;
60    }
61}
62
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     * Calculates the sum of values of all nodes at the deepest level of the binary tree.
16     * Uses BFS (level-order traversal) to process the tree level by level.
17     * 
18     * @param root The root node of the binary tree
19     * @return The sum of all node values at the deepest level
20     */
21    int deepestLeavesSum(TreeNode* root) {
22        int currentLevelSum = 0;
23      
24        // Initialize queue for BFS with the root node
25        std::queue<TreeNode*> bfsQueue;
26        bfsQueue.push(root);
27      
28        // Process tree level by level
29        while (!bfsQueue.empty()) {
30            // Reset sum for current level
31            currentLevelSum = 0;
32          
33            // Get the number of nodes at current level
34            int nodesAtCurrentLevel = bfsQueue.size();
35          
36            // Process all nodes at current level
37            for (int i = 0; i < nodesAtCurrentLevel; ++i) {
38                // Get and remove the front node from queue
39                TreeNode* currentNode = bfsQueue.front();
40                bfsQueue.pop();
41              
42                // Add current node's value to level sum
43                currentLevelSum += currentNode->val;
44              
45                // Add left child to queue for next level processing
46                if (currentNode->left != nullptr) {
47                    bfsQueue.push(currentNode->left);
48                }
49              
50                // Add right child to queue for next level processing
51                if (currentNode->right != nullptr) {
52                    bfsQueue.push(currentNode->right);
53                }
54            }
55        }
56      
57        // Return the sum of the last (deepest) level processed
58        return currentLevelSum;
59    }
60};
61
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 * Calculates the sum of values of all nodes at the deepest level of a binary tree.
17 * Uses BFS (Breadth-First Search) to traverse the tree level by level.
18 * 
19 * @param root - The root node of the binary tree
20 * @returns The sum of all node values at the deepest level
21 */
22function deepestLeavesSum(root: TreeNode | null): number {
23    // Handle edge case of empty tree
24    if (!root) {
25        return 0;
26    }
27  
28    // Initialize queue for BFS with root node
29    let currentLevelNodes: TreeNode[] = [root];
30    let deepestLevelSum: number = 0;
31  
32    // Process tree level by level until we reach the deepest level
33    while (currentLevelNodes.length > 0) {
34        // Prepare queue for next level nodes
35        const nextLevelNodes: TreeNode[] = [];
36      
37        // Reset sum for current level
38        deepestLevelSum = 0;
39      
40        // Process all nodes in current level
41        for (const node of currentLevelNodes) {
42            // Add current node's value to sum
43            deepestLevelSum += node.val;
44          
45            // Add left child to next level if it exists
46            if (node.left) {
47                nextLevelNodes.push(node.left);
48            }
49          
50            // Add right child to next level if it exists
51            if (node.right) {
52                nextLevelNodes.push(node.right);
53            }
54        }
55      
56        // Move to next level
57        currentLevelNodes = nextLevelNodes;
58    }
59  
60    // Return sum of the deepest level (last level processed)
61    return deepestLevelSum;
62}
63

Time and Space Complexity

Time Complexity: O(n), where n is the number of nodes in the binary tree.

The algorithm uses BFS (Breadth-First Search) to traverse the tree level by level. Each node in the tree is visited exactly once - it's added to the queue once and processed once when it's dequeued. For each node, we perform constant time operations: adding its value to the sum and checking/adding its children to the queue. Since we visit all n nodes exactly once and perform O(1) operations for each node, the total time complexity is O(n).

Space Complexity: O(n), where n is the number of nodes in the binary tree.

The space complexity is determined by the maximum size of the queue at any point during execution. In the worst case, the queue will contain all nodes at the widest level of the tree. For a perfectly balanced binary tree, the last level contains approximately n/2 nodes, making the space complexity O(n/2) = O(n). Even in other tree configurations (like a skewed tree where each level has only one node), the queue size is bounded by O(n) in the worst case.

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

Common Pitfalls

1. Not Handling Edge Cases Properly

Pitfall: The code assumes the root is always valid (non-None). If someone passes None as the root, the code will crash when trying to add it to the queue.

Issue Example:

# This will cause an error
solution.deepestLeavesSum(None)  # TypeError when processing None

Solution: Add a null check at the beginning:

def deepestLeavesSum(self, root: Optional[TreeNode]) -> int:
    if not root:
        return 0
  
    queue = deque([root])
    # ... rest of the code

2. Confusing Deepest Leaves with All Leaves

Pitfall: Misunderstanding the problem and trying to sum ALL leaf nodes instead of only the deepest ones. Someone might try to check if a node is a leaf and accumulate only those values.

Incorrect Approach:

# Wrong - this sums all leaves, not just deepest ones
total_sum = 0
for _ in range(level_size):
    current_node = queue.popleft()
    # Checking if it's a leaf - WRONG for this problem!
    if not current_node.left and not current_node.right:
        total_sum += current_node.val

Solution: The original approach is correct - sum ALL nodes at each level and keep overwriting. The last level will naturally contain only leaves since they have no children to add to the queue.

3. Using Wrong Queue Operations

Pitfall: Using pop() instead of popleft() or regular list operations, which changes the traversal from BFS to something else.

Incorrect:

# Using pop() removes from the end - this breaks level-order traversal
current_node = queue.pop()  # Wrong!

# Or using a list with inefficient operations
queue = [root]
current_node = queue.pop(0)  # O(n) operation, inefficient

Solution: Always use deque with popleft() for O(1) removal from the front:

from collections import deque
queue = deque([root])
current_node = queue.popleft()  # Correct and efficient

4. Not Capturing Level Size Before Processing

Pitfall: Using len(queue) directly in the loop condition, which changes as nodes are added/removed.

Incorrect:

# Wrong - len(queue) changes during iteration
for i in range(len(queue)):  # If used without storing first
    current_node = queue.popleft()
    # Adding children changes len(queue)
    if current_node.left:
        queue.append(current_node.left)

Solution: Always capture the level size before the loop:

level_size = len(queue)  # Capture size first
for _ in range(level_size):  # Now it's fixed
    # Process nodes

5. Memory Optimization Confusion

Pitfall: Trying to optimize by keeping track of only leaf sums, which adds unnecessary complexity.

Overcomplication:

# Unnecessary - tracking depth and leaf status
max_depth = 0
leaf_sums = {}
# Complex logic to track depths and check leaves

Solution: The simple approach of overwriting the sum for each level is already optimal - no need to track depths or distinguish leaves explicitly.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the following uses divide and conquer strategy?


Recommended Readings

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

Load More