You are given the root
of a binary tree. Your task is to return the sum of values of its deepest leaves. A deepest leaf is a node with no children that is farthest from the root. For example, a tree with only the root node has a single deepest leaf, the root itself.
Consider the following examples:
Input: root = [1,2,3,4,5,null,6,7,null,null,null,null,8]
Output: 15
Explanation: The deepest leaves are the nodes with values 7 and 8. Therefore, the sum is 7 + 8 = 15.
Input: root = [6,7,8,2,7,1,3,9,null,1,4,null,null,null,5]
Output: 19
Explanation: The deepest leaves are the nodes with values 9, 1, 4, and 5. Therefore, the sum is 9 + 1 + 4 + 5 = 19.
Given these examples, write an algorithm to efficiently calculate the sum of the values of the deepest leaves in a given binary tree. What is the time and space complexity of your solution?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The core idea is to explore every single path from the top of the tree down to the leaves. We will find the depth of each leaf and keep track of the deepest level we encounter. Then we'll sum up the values of all the leaves at that deepest level.
Here's how the algorithm would work step-by-step:
def deepest_leaves_sum(root):
deepest_level = 0
leaves_sums = 0
def dfs(node, level):
nonlocal deepest_level, leaves_sums
# If we hit a null node, simply return.
if not node:
return
# If we hit a leaf node, check if we need to update deepest_level and leaves_sums.
if not node.left and not node.right:
if level > deepest_level:
# We have a new deepest level
deepest_level = level
leaves_sums = node.val
elif level == deepest_level:
# Accumulate nodes at the deepest level
leaves_sums += node.val
return
dfs(node.left, level + 1)
dfs(node.right, level + 1)
dfs(root, 0)
return leaves_sums
The most efficient way to find the sum of the deepest leaves is to explore the tree level by level. We keep track of the current deepest level and its corresponding sum, updating it whenever we encounter a new deepest level.
Here's how the algorithm would work step-by-step:
def deepestLeavesSum(root):
deepest_level_sum = 0
max_depth = -1
def dfs(node, current_depth):
nonlocal deepest_level_sum, max_depth
if not node:
return
#If deeper level found, reset sum
if current_depth > max_depth:
deepest_level_sum = node.val
max_depth = current_depth
elif current_depth == max_depth:
#If same level, add to the sum
deepest_level_sum += node.val
dfs(node.left, current_depth + 1)
dfs(node.right, current_depth + 1)
dfs(root, 0)
return deepest_level_sum
Case | How to Handle |
---|---|
Null root node | Return 0 immediately as there are no nodes to sum. |
Single node tree | Return the value of the root node since it's the only deepest node. |
Tree with all positive values | Standard traversal will correctly calculate the sum. |
Tree with all negative values | Standard traversal will correctly calculate the negative sum. |
Tree with a mix of positive, negative and zero values | Standard traversal will correctly handle the sum. |
Deeply skewed tree (e.g., linked list structure) | The depth-first or breadth-first traversal should handle potentially large depth without stack overflow issues for a balanced input, although highly unbalanced inputs may impact recursion depth. |
Maximum integer value for node values to detect integer overflow | Use long data type for storing sum to prevent potential integer overflow when summing the values at deepest level. |
Perfectly balanced tree with large number of nodes | BFS approach might consume a lot of memory in the queue; DFS is typically more memory-efficient for balanced trees. |