Path Sum III
You are given the root of a binary tree and an integer targetSum. Count the downward paths whose node values add up to exactly targetSum.
A downward path is a sequence of one or more nodes in which every node is the parent of the next one. It may start at any node, not only the root, and may stop at any node, not only a leaf, but it can never go back up toward the root.
Node values may be negative or zero, so several different paths can share nodes and still count separately.
The tree is given as a level-order array in which null marks a missing child.
Example 1
Example 2
Example 3
Constraints
- The number of nodes is between 0 and 1000.
-109 <= Node.val <= 109-1000 <= targetSum <= 1000
Pattern Path · Trees: DFS · problem 90 of 169
running - prefix(A). Keep a count of the prefix sums on the current route in a hash map.running - targetSum before descending, add the current sum to the map, recurse, then remove it on the way back up so other branches do not see it.Start simple
Start a depth-first walk from every node and count how many partial sums along each walk equal the target: O(n·h) time, which is O(n²) for a skewed tree.
The key idea
Fix the node where a path ends. The route from the root to that node is a simple list of values, and every downward path ending there is a suffix of that list. This turns the tree problem into the classic "count subarrays with a given sum" problem, applied along each root-to-node route.
Let running be the sum from the root to the current node. A path starting just below some ancestor whose prefix sum is p has sum running - p, so it equals the target exactly when p = running - targetSum. A hash map from prefix sum to how many times it appears on the current route answers "how many such ancestors are there?" in O(1). Seeding the map with {0: 1} accounts for paths that start at the root.
During the depth-first search, add the current prefix sum to the map before visiting the children and remove it afterwards. That backtracking step keeps the map describing only the current root-to-node route, so a path can never jump between sibling branches.
Every node is visited once with O(1) map work, giving linear time.
Complexity
- Time:
O(n) - Space:
O(n)
Python
from collections import defaultdict
class Solution:
def pathSum(self, root, targetSum):
# How many times each prefix sum occurs on the current root-to-node route.
prefix_counts = defaultdict(int)
prefix_counts[0] = 1 # the empty prefix, for paths starting at the root
def dfs(node, running):
if node is None:
return 0
running += node.val
# Paths ending here start right after an ancestor whose prefix is running - targetSum.
count = prefix_counts[running - targetSum]
prefix_counts[running] += 1
count += dfs(node.left, running) + dfs(node.right, running)
prefix_counts[running] -= 1 # leave this branch: forget its prefix
return count
return dfs(root, 0)
JavaScript
var pathSum = function(root, targetSum) {
// How many times each prefix sum occurs on the current root-to-node route.
const prefixCounts = new Map([[0, 1]]);
const dfs = (node, running) => {
if (node === null) return 0;
running += node.val;
// Paths ending here start right after an ancestor whose prefix is running - targetSum.
let count = prefixCounts.get(running - targetSum) || 0;
prefixCounts.set(running, (prefixCounts.get(running) || 0) + 1);
count += dfs(node.left, running) + dfs(node.right, running);
prefixCounts.set(running, prefixCounts.get(running) - 1); // leave this branch
return count;
};
return dfs(root, 0);
};
What the interviewer is checking
It tests whether you can recognise the prefix-sum-plus-hash-map trick in a new setting and handle the backtracking that keeps the state scoped to one branch.
Mistakes to avoid
- Forgetting to seed the map with prefix sum 0, which misses paths that start at the root.
- Not removing the current prefix sum after visiting the children, so sums leak into sibling subtrees.
- Stopping a walk as soon as the target is reached; with zeros and negatives, longer paths may hit the target again.
- Overflowing 32-bit integers in Java or C++: sums of values up to 109 need 64-bit types.
Follow-ups to expect
- Can you also return the paths themselves? (Store ancestor lists, output-sensitive cost.)
- What if paths could bend through a parent? (Combine left and right sums per node.)
- How would you avoid deep recursion? (Iterative DFS with explicit stack.)
In real software
Running totals with a lookup of earlier totals power queries such as "how many periods in this history had net change X", for example in financial ledgers or hierarchical cost reports.