Algorithm

Path Sum

Trees Pattern

Path Sum

Given the root of a binary tree and an integer targetSum, return true if there exists a root-to-leaf path whose node values add up to exactly targetSum, and false otherwise. The path must start at the root and end at a leaf (a node with no children); a partial path that happens to reach the target partway down does not count. An empty tree contains no path at all, so it returns false for every target, including 0.

CONSTRAINTS
  • The number of nodes in the tree is in the range [0, 5000]
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000
  • The path must end at a leaf, not at an internal node
EXAMPLE 1
Input: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
Output: true
The path 5, 4, 11, 2 adds to 22 and ends at the leaf 2. Only one qualifying path is needed — the others may miss the target entirely.
EXAMPLE 2
Input: root = [1,2,3], targetSum = 1
Output: false
The root alone is worth 1, but the root is not a leaf, so stopping there is not a legal path. The two real paths total 3 and 4.
EXAMPLE 3
Input: root = [1,-2,3], targetSum = -1
Output: true
1 + (-2) = -1 at the leaf -2. Negative values mean the running total can fall as you descend, so a total that has already overshot the target may still come back.
EXAMPLE 4
Input: root = [], targetSum = 0
Output: false
There are no leaves, so there is no path whose values could sum to anything — even a target of 0 has nothing to match.
Must the path end at a leaf?
Yes, and this is the trap in the problem. Hitting the target at an internal node does not count, so the check has to be tied to leaf-ness, not to the total alone.
Can values be negative?
Yes, from -1000 up. That rules out any 'stop early once the running sum exceeds the target' pruning, since a later negative can bring it back down.
What is the answer for an empty tree with target 0?
False. It is tempting to say the empty path sums to 0, but the problem requires an actual root-to-leaf path, and an empty tree has none.
Do I need to return the path itself?
No, just true or false. The follow-up that asks for every qualifying path (Path Sum II) needs backtracking on top of this, which changes the cost.

We want to know whether some root-to-leaf route adds up to the target. This is a search over routes, and the route information again comes from above — a leaf has no idea what was added on the way to it — so this is the downward-flowing shape from Binary Tree Paths, with a number carried instead of a list.

Two ways to carry the number, one clearly better

You could carry the running sum accumulated so far, and compare against the target on arrival at a leaf. That works. The slightly cleaner variant carries what is still owed: start with the target, and at each node subtract that node's value before descending. Then the two children inherit the amount remaining to be covered by the rest of the route, and there is only one number to pass instead of two.

At a leaf, the route is finished. It qualifies precisely when nothing is left owing — the remainder is exactly 0. Not "at most 0", not "close to 0": the sum must land on the target exactly.

For a node that is not a leaf, the answer is that either child can rescue it:

text
canReach(node, need) = canReach(node.left, need - node.val)  OR  canReach(node.right, need - node.val)

and canReach(null, anything) = false — an absent subtree offers no route.

python
def hasPathSum(node, need):
    if node is None:
        return False                     # no route through nothing
    need -= node.val                     # pay this node out of what is owed
    if node.left is None and node.right is None:
        return need == 0                 # a leaf: the route ends here, so it must balance exactly
    return hasPathSum(node.left, need) or hasPathSum(node.right, need)
Crucial Notethe null base case returning false and the leaf check are doing different jobs, and collapsing them breaks the problem. If you drop the leaf test and instead let a null node answer need == 0, then a node with exactly one child gets asked about its missing side — with the full remainder still outstanding — and if that remainder happens to be 0, you return true for a route that stops in mid-air at an internal node. The second example is exactly this trap: the root alone equals the target, and any solution that does not insist on a leaf reports true.
Why negatives forbid the obvious shortcut

A tempting optimisation: abandon a branch as soon as the remainder goes negative, since we have already overshot. That is valid only when every value is non-negative, because then the running sum can never come back down. Here values go down to -1000, so a route that has overshot by 50 can be rescued by a -50 further along, and pruning would discard genuine answers. The precondition matters more than the trick — before pruning a search, always ask what property of the input makes the discarded region provably useless. Here there is no such property, so we visit everything.

Short-circuiting on success is still fine, though: or stops as soon as the left subtree reports true, so the search ends the moment one qualifying route is found. That is a genuine saving on lucky inputs and costs nothing.

Worked example:the tree rooted at 5, with target 22
The tree: 5 has children 4 and 8; 4 has left child 11; 11 has children 7 and 2; 8 has children 13 and 4; that second 4 has right child 1.
- At 5, need = 22 - 5 = 17. Not a leaf, so descend left.
- At 4, need = 17 - 4 = 13. Not a leaf. Its right is null (returns false immediately), so effectively only 11 matters.
- At 11, need = 13 - 11 = 2. Not a leaf. Left first.
- At 7, need = 2 - 7 = -5. This is a leaf, and -5 ≠ 0, so false. The route 5, 4, 11, 7 sums to 27, overshooting.
- Back at 11, try the right. At 2, need = 2 - 2 = 0, and it is a leaf — true.
- That true rides straight back up through 11, 4 and 5, and the entire right subtree under 8 is never examined.
Cost, and the shape to keep

Worst case every node is visited once, doing constant work: O(N) time. Space is the recursion stack, O(H) — logarithmic on a balanced tree, but up to 5000 frames on a chain. Nothing is stored per path, because we only ever needed one number in flight, which is precisely why this is cheaper than Binary Tree Paths despite the identical traversal.

The transferable move is the reframing from "accumulate and compare at the end" to "carry what remains." It converts a two-value comparison into a single-value target of zero, and it generalises well beyond trees — it is the same substitution that makes subset-sum and coin-change recursions readable. And keep the leaf-versus-null distinction in the front of your mind: the base case that stops you falling off the structure is never the same thing as the condition that makes an answer complete. Sum Root to Leaf Numbers carries a number down in the same way, but builds it by multiplying by ten instead of subtracting — same skeleton, different arithmetic in the one slot that varies.

Interactive Strategy Visualization

Path Sum Calculus

Subtraction Logic: Goal (22)

54117281341
Root (5). Remaining required: 22 - 5 = 17.
Recursive State
Target Check
22
Remaining needed for leaf

Subtracting node value from goal as we go deeper.

"Success if target becomes 0 at a node with no children."

Strategy

Recursive decomposition: `hasPathSum(root, sum) = hasPathSum(root.left, sum - val) || hasPathSum(root.right, sum - val)`.

"Reduce target at every step."

O(N × H) Build Every Path Then Sum
O(N) Time · O(H) Space Carry The Remainder Down