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:
- Tree Structure: Binary trees are naturally suited for DFS traversal patterns
- Depth Information: DFS can easily track the depth/level of each node as we traverse
- Recursive Nature: The problem can be solved by recursively exploring each branch while maintaining depth information
DFS Solution Approach
Using DFS, we can:
- Traverse the tree while keeping track of the current depth
- Maintain a record of the maximum depth encountered
- 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.
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:
-
Initialize the Queue: Start by adding the root node to the queue
q = deque([root])
. -
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. -
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. -
Process Current Level: The inner loop
for _ in range(len(q)):
ensures we process exactly the nodes that belong to the current level. Thelen(q)
at the start of the loop captures the number of nodes at this level. -
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)
- Remove it from the front of the queue:
-
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 EvaluatorExample 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.
Which of the following uses divide and conquer strategy?
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!