Given the root of a binary tree, return the maximum path sum of any non-empty path.
A path is any sequence of nodes connected by edges, where each node appears at most once; it need not pass through the root. The path sum is the sum of the nodes' values. Node values may be negative.
The tree is given in level-order (breadth-first), using null for missing children.
Input: root = [1, 2, 3] Output: 6 The path 2 -> 1 -> 3 sums to 6.
Input: root = [-10, 9, 20, null, null, 15, 7] Output: 42 The path 15 -> 20 -> 7 sums to 42; going up to -10 would only reduce it.
- The number of nodes is in the range [1, 3 * 10^4] - -1000 <= Node.val <= 1000
This is the diameter pattern with values instead of edge counts, plus one twist: a negative branch should be dropped (contribute 0) rather than dragging the sum down. Each call returns the best single downward path (clamped at 0), while recording the best path that bends at the node — node.val + leftGain + rightGain.
“Can the path be a single node?”
Yes — the path is non-empty, so the answer can be a lone (possibly negative) node.
“Can values be negative?”
Yes, which is why negative branches are clamped to 0 before combining.
For each node, the best path bending at it is the node's value plus the best downward gain from each side, where a negative side contributes zero.
Each call returns the value plus its single best downward branch so the parent can extend it, while I keep a global maximum of the bending paths.
Worked example — tree [-10, 9, 20, null, null, 15, 7]
-10
/ \
9 20
/ \
15 7
gain(15)=15, gain(7)=7 -> at 20: bend = 20+15+7 = 42 (best)
at -10: l=max(9,0)=9, r=max(gain(20)=20+15=35,0)=35 -> bend = -10+9+35 = 34
answer: 42
A branch with a negative gain only reduces the sum, so treat it as unused (0) rather than subtracting.
The global answer can use both children (a path bending at the node); the value passed up can extend only a single branch.
Because a single negative node can be the best path, initialize the global maximum below any possible value.
| Recompute gains per node | Single-pass gain + record | |
|---|---|---|
| Idea | At each node, recompute both downward gains | One postorder pass; record bend, return one branch |
| Time | O(n^2) | O(n) |
| Space | O(height) | O(height) |
The single-pass version reuses each gain. Full code is in the Approaches selector below.
Key takeaway
For each node, the bending path is node.val + max(gainL, 0) + max(gainR, 0); record it globally and return node.val + max(gainL, gainR, 0) upward. Start the answer at −∞. O(n) time, O(height) space.
gain(node):
if node is null: return 0
l = max(gain(node.left), 0)
r = max(gain(node.right), 0)
best = max(best, node.val + l + r)
return node.val + max(l, r)