Example 1
ready- Input
root = [ 1, 2, 3 ]- Expected
6- Why
- the route 2 → 1 → 3 collects all three values
Picture each tree node as a checkpoint that adds points or charges a cost. The richest route may climb out of one branch, cross the node where two branches meet, and finish in another without ever touching the root.
A path is a sequence of nodes where each neighboring pair shares an edge. Given the root of a non-empty binary tree, return the largest sum you can collect along any path.
A few ground rules:
1 <= node count <= 10_000-1_000 <= node.val <= 1_000root is never null.Hints
A path that bends through the current node may collect one useful contribution from the left child and one from the right child. What should happen to a contribution whose total is negative?
A parent can extend only one branch from its child. Returning both branches would create a fork, not a path. Keep the better single branch for the parent, but test both branches together as an answer at the current node.
Clamp a harmful child contribution to zero. Keep the global answer initialized to a real node value, though, or an all-negative tree will incorrectly return the empty path.
How would you return the actual sequence of nodes on a maximum-sum path while keeping the same O(n) running time?
Visible cases
root = [
1,
2,
3
]6root = [
-10,
9,
20,
null,
null,
15,
7
]42root = [
-3
]-3Interview signal
The trap is subtle: one path can use both child branches at its turning point, but only one of those branches can continue upward to a parent. Keep those two jobs separate.
A tree has exactly one route between any two nodes. Treat each edge as two-way, record every node's parent, then choose every possible starting node and walk to every reachable endpoint. The running total on each walk is one candidate path sum.
def max_path_sum(root: TreeNode) -> int:
nodes: list[TreeNode] = []
parent: dict[TreeNode, TreeNode | None] = {root: None}
stack = [root]
while stack:
node = stack.pop()
nodes.append(node)
if node.left is not None:
parent[node.left] = node
stack.append(node.left)
if node.right is not None:
parent[node.right] = node
stack.append(node.right)
best = root.val
for start in nodes:
paths = [(start, None, start.val)]
while paths:
node, previous, total = paths.pop()
best = max(best, total)
for neighbor in (node.left, node.right, parent[node]):
if neighbor is not None and neighbor is not previous:
paths.append((neighbor, node, total + neighbor.val))
return bestTime O(n²) — each of n starting nodes can visit all n nodes. Space O(n) for the parent map, node list, and traversal stack.
A post-order traversal processes both children before their parent. That timing lets each child report a downward arm — the best path that starts at that child and follows at most one child branch.
At node, clamp each child's arm to zero because extending through a negative total can
only hurt. Two different calculations now matter:
node.val + left_gain + right_gain is the best complete path whose turning point is
node. It may bend through both children, so use it to update the global answer.node.val + max(left_gain, right_gain) is the one arm the parent may extend. Clamp
that result to zero before returning it.import sys
def max_path_sum(root: TreeNode) -> int:
sys.setrecursionlimit(20_000)
best = root.val
def best_arm(node: TreeNode | None) -> int:
nonlocal best
if node is None:
return 0
left_gain = best_arm(node.left)
right_gain = best_arm(node.right)
best = max(best, node.val + left_gain + right_gain)
return max(0, node.val + max(left_gain, right_gain))
best_arm(root)
return bestWhy does this cover every answer? Take any path and find its highest node in the rooted tree. The path uses at most one downward arm from each child of that node, exactly the candidate the traversal evaluates there. Since every node gets that chance, the best candidate can't be missed.
Initialize best from a real node, not zero. Returned arms may discard a loss, but the
final path may never be empty; a tree full of negative values must return its least
negative node.
Time O(n) — every node is processed once. Space O(h) for the recursion stack,
where h is the tree height; the raised recursion limit covers the allowed skewed case.
Ready to run.
3 cases are queued.
Visible testcase
Case 1
Expected
6