A clear explanation of the Sum of Left Leaves problem using depth-first traversal of a binary tree.
Problem Restatement
We are given the root of a binary tree.
A leaf node is a node with no children:
node.left is None and node.right is NoneA left leaf is a leaf node that is also the left child of its parent.
We must return the sum of all left leaves in the tree.
Input and Output
| Item | Meaning |
|---|---|
| Input | The root of a binary tree |
| Output | The sum of all left leaf values |
| Leaf node | A node with no children |
| Left leaf | A leaf that is the left child of its parent |
Example function shape:
def sumOfLeftLeaves(root: Optional[TreeNode]) -> int:
...Examples
Consider this tree:
image_group{“layout”:“carousel”,“aspect_ratio”:“16:9”,“query”:[“binary tree left leaves example diagram”,“sum of left leaves leetcode 404 tree”,“binary tree left leaf illustration”,“tree traversal left leaf example”],“num_per_query”:1}
3
/ \
9 20
/ \
15 7The left leaves are:
9
15Both are left children, and both are leaves.
So the answer is:
9 + 15 = 24Another example:
1The tree contains only one node.
The root is not considered a left leaf because it has no parent.
So the answer is:
0First Thought: Traverse Every Node
We can visit every node in the tree.
For each node:
- Check whether its left child exists.
- Check whether that left child is a leaf.
- If yes, add its value to the answer.
- Continue traversing the tree.
This naturally suggests depth-first search.
Key Insight
A node itself does not know whether it is a left child.
That information comes from its parent.
So instead of asking:
"is this node a left leaf?"we can ask:
"does this node have a left child that is a leaf?"This makes the recursion simpler.
At each node:
- Inspect the left child.
- Add its value if it is a leaf.
- Recurse into both subtrees.
Algorithm
Define a recursive DFS function.
For each node:
- If the node is
None, return0. - Initialize the current contribution as
0. - If the node has a left child:
- Check whether that child is a leaf.
- If yes, add its value.
- Recurse into the left subtree.
- Recurse into the right subtree.
- Return the total sum.
Correctness
We prove that the algorithm returns the sum of all left leaves in the tree.
For every node in the tree, the algorithm checks whether its left child exists and whether that left child is a leaf.
A node is a left leaf exactly when:
it is a left child
and
it has no childrenThe algorithm identifies such nodes precisely by inspecting the left child of each parent node.
If a left child is a leaf, its value is added exactly once.
No right leaf is added, because the algorithm only checks left children.
No non-leaf node is added, because the algorithm requires both children to be None.
The recursive traversal visits every node in the tree, so every possible left leaf is checked.
Therefore, the returned sum is correct.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(n) | Every node is visited once |
| Space | O(h) | Recursive call stack height |
Where:
| Symbol | Meaning |
|---|---|
n | Number of nodes |
h | Height of the tree |
In the worst case of a skewed tree:
h = nIn a balanced tree:
h = log nImplementation
from typing import Optional
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
def dfs(node: Optional[TreeNode]) -> int:
if not node:
return 0
total = 0
if node.left:
left = node.left
if left.left is None and left.right is None:
total += left.val
total += dfs(node.left)
total += dfs(node.right)
return total
return dfs(root)Code Explanation
We define a recursive helper:
dfs(node)This returns the sum of left leaves inside the subtree rooted at node.
The base case is:
if not node:
return 0An empty subtree contributes nothing.
We initialize:
total = 0Then we inspect the left child:
if node.left:If it exists, we check whether it is a leaf:
if left.left is None and left.right is None:If true, we add its value:
total += left.valThen we continue searching both subtrees:
total += dfs(node.left)
total += dfs(node.right)Finally, we return the accumulated sum.
Testing
def test_sum_of_left_leaves():
s = Solution()
root1 = TreeNode(
3,
TreeNode(9),
TreeNode(
20,
TreeNode(15),
TreeNode(7),
),
)
assert s.sumOfLeftLeaves(root1) == 24
root2 = TreeNode(1)
assert s.sumOfLeftLeaves(root2) == 0
root3 = TreeNode(
1,
TreeNode(
2,
TreeNode(4),
TreeNode(5),
),
TreeNode(3),
)
assert s.sumOfLeftLeaves(root3) == 4
root4 = TreeNode(
1,
None,
TreeNode(2),
)
assert s.sumOfLeftLeaves(root4) == 0
root5 = TreeNode(
1,
TreeNode(
2,
TreeNode(
3,
TreeNode(4),
None,
),
None,
),
None,
)
assert s.sumOfLeftLeaves(root5) == 4
print("all tests passed")Test Notes
| Test | Why |
|---|---|
| Standard example tree | Checks multiple left leaves |
| Single-node tree | Root is not a left leaf |
| Mixed left and right leaves | Only left leaves should count |
| Tree with only right child | Result should be zero |
| Deep skewed tree | Checks recursive traversal depth |