Problem
Given a binary tree and a target sum, find every root-to-leaf path whose node values add up to exactly that target. A leaf is a node with no children โ paths must terminate at a leaf.
[5,4,8,11,null,13,4,7,2,null,null,5,1]
- Input: root = above tree, targetSum = 22
- Output: [[5,4,11,2],[5,8,4,5]]
- Explanation: both paths reach a leaf and their values sum to 22
A counter-example: the path 5โ8โ4โ1 sums to 18, not 22, so it is excluded even though it ends at a leaf.
Intuition
The problem is a classic tree enumeration: visit every root-to-leaf path and collect the ones that hit the target. The key insight is that you can track a decreasing remainder as you go deeper โ subtract each node's value from the remaining target, and whenever you land on a leaf with zero left over, you have a valid path. Backtracking lets you undo each step and explore sibling subtrees without allocating a new list per call.
Solution โ DFS with Backtracking
Carry a single mutable path list down the tree, appending each node's value and removing it after both children have been explored. When a leaf is reached with zero remaining sum, snapshot the current path into results.
- Define a recursive helper that takes the current node, remaining target, and path list.
- Return immediately if the node is
null. - Append the node's value to the path and subtract it from the remaining target.
- If the node is a leaf and remaining is exactly zero, copy the path into results.
- Recurse into the left child, then the right child.
- Pop the node's value from the path to backtrack before returning to the caller.
1def pathSum(root, targetSum):
2 result = []
3
4 def dfs(node, remaining, current_path):
5 if not node:
6 return
7
8 current_path.append(node.val)
9 remaining -= node.val
10
11 # Only record at a true leaf โ nodes with one child don't count
12 if not node.left and not node.right and remaining == 0:
13 result.append(list(current_path)) # copy, not reference
14
15 dfs(node.left, remaining, current_path)
16 dfs(node.right, remaining, current_path)
17
18 current_path.pop() # undo this node before returning to parent
19
20 dfs(root, targetSum, [])
21 return resultTime: O(nยฒ) โ every node is visited once, and copying a valid path takes O(h); in the worst case (many valid paths in a dense tree) total copy work reaches O(nยฒ).
Space: O(h) auxiliary โ the recursion stack and current path together hold at most one full root-to-leaf path at a time; output space for the collected paths is additional.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| DFS with backtracking | O(nยฒ) | O(h) auxiliary | Whenever you need all root-to-leaf paths โ this is the canonical approach |
Common Mistakes
- Saving the path list directly instead of copying it โ
result.append(current_path)stores a reference to the same list that gets cleared during backtracking;result.append(list(current_path))(ornew ArrayList<>(currentPath)in Java) creates a snapshot. - Triggering the result check at non-leaf nodes โ a node with one child where
remaining == 0is NOT a valid endpoint; the condition must checknot node.left and not node.rightbefore recording the path. - Forgetting to pop after recursing into both children โ without the backtrack step, every subsequent path inherits garbage values from earlier branches, producing wrong-length paths.
- Skipping the single-node edge case โ a tree with just one node whose value equals
targetSumis a valid path; the leaf check naturally covers this, but forgetting thenot node.left and not node.rightguard does not. - Confusing Path Sum with Path Sum III โ this problem only allows root-to-leaf paths; Path Sum III allows paths starting and ending at any node, which requires a completely different prefix-sum approach.
Related Problems
Path Sumโ same DFS pattern but returns a boolean instead of collecting pathsPath Sum IIIโ extends to any node-to-node paths using prefix sums; same tree traversal but fundamentally different trackingSum Root to Leaf Numbersโ root-to-leaf paths treated as decimal numbers; same backtracking skeletonBinary Tree Maximum Path Sumโ generalizes path sum to any node-to-node path and seeks the maximum, requiring a different return value from the recursive helperPath with Maximum Goldโ grid-based backtracking collecting path values, same "accumulate then undo" structure