Example 1
ready- Input
root = [ 5, 4, 8, 11, null, 13, 4, 7, 2, null, null, null, 1 ] targetSum = 22- Expected
true- Why
- the route 5 → 4 → 11 → 2 ends at a leaf and totals 22
A route can hit the right total halfway down a tree and still be the wrong route. The finish line matters.
Given a binary tree's root and an integer targetSum, return true when at least one
root-to-leaf path — a downward route that starts at the root and ends at a node with
no children — has values adding to exactly targetSum.
Keep the endpoint rule sharp:
false.0 <= number of nodes <= 10_000-1_000 <= node.val <= 1_000-100_000_000 <= targetSum <= 100_000_000Hints
The direct approach collects the sum of each complete root-to-leaf route, then asks
whether targetSum appears in that collection.
Instead of rebuilding a path at every leaf, subtract each visited value from the target. What must the remainder be when you reach a leaf?
A remainder of zero is an answer only when the current node has no children. Otherwise the route hasn't finished.
How would you return one matching root-to-leaf path instead of only true or false?
Visible cases
root = [
5,
4,
8,
11,
null,
13,
4,
7,
2,
null,
null,
null,
1
]
targetSum = 22trueroot = [
1,
2,
3
]
targetSum = 5falseroot = []
targetSum = 0falseInterview signal
Keep the values on the current route. At each leaf, sum that route and save the result. After every leaf has reported, check whether the target appears among the totals.
def has_path_sum(root: TreeNode | None, target_sum: int) -> bool:
if root is None:
return False
path: list[int] = []
path_sums: list[int] = []
def collect(node: TreeNode) -> None:
path.append(node.val)
if node.left is None and node.right is None:
path_sums.append(sum(path))
else:
if node.left is not None:
collect(node.left)
if node.right is not None:
collect(node.right)
path.pop()
collect(root)
return target_sum in path_sumsThis works, but sum(path) repeats work already done for the parent route.
Time O(nh) in the worst case — leaf totals may each scan a path of height h.
Space O(h + L) — the current path uses h slots and the saved totals use one slot
per leaf, L.
When you enter a node, subtract its value from the remaining target. At a leaf, the route matches exactly when that remainder is zero. Otherwise, pass the smaller question to both children.
def has_path_sum(root: TreeNode | None, target_sum: int) -> bool:
if root is None:
return False
remaining = target_sum - root.val
if root.left is None and root.right is None:
return remaining == 0
return (
has_path_sum(root.left, remaining)
or has_path_sum(root.right, remaining)
)The leaf check prevents the classic false positive: matching the target at an internal
node and stopping before the route is complete. The or also short-circuits as soon as
one finished route matches.
Time O(n) — each node is visited at most once. Space O(h) — recursion holds one root-to-leaf route.
Python's call stack may fail on the valid 1,200-node line in the hidden suite. Keep the same remaining-target state in an explicit stack when depth is untrusted:
def has_path_sum_iterative(root: TreeNode | None, target_sum: int) -> bool:
if root is None:
return False
stack = [(root, target_sum - root.val)]
while stack:
node, remaining = stack.pop()
if node.left is None and node.right is None and remaining == 0:
return True
if node.left is not None:
stack.append((node.left, remaining - node.left.val))
if node.right is not None:
stack.append((node.right, remaining - node.right.val))
return FalseThat version keeps O(n) time and O(h) space without depending on Python's recursion limit.
Ready to run.
3 cases are queued.
Visible testcase
Case 1
Expected
true