What you return and what you measure can differ
Picture
A tree’s diameter is the largest number of edges on any simple path between two nodes. At a node, a candidate path can join the deepest left branch to the deepest right branch. But a parent can extend only one branch of that path, so the upward summary is different from the candidate answer.
Predict
Child subtree heights, measured in nodes, are 3 and 5. What diameter candidate passes through the current node, and what height should it return upward?
Reveal the reasoning
The candidate has 3+5=8 edges. The returned height is 1+max(3,5)=6 nodes. Returning the full two-branch candidate as a height would let an ancestor build a branching object rather than a simple path.
Go deeper: evaluate every possible meeting point once
def diameter(root):
longest = 0
def height(node):
nonlocal longest
if node is None:
return 0
_, left, right = node
left_height = height(left)
right_height = height(right)
longest = max(longest, left_height + right_height)
return 1 + max(left_height, right_height)
height(root)
return longest
tree = (1, (2, (4, None, None), (5, None, None)), (3, None, None))
assert diameter(tree) == 3
assert diameter((1, None, None)) == 0
assert diameter(None) == 0
Every simple tree path has a highest node relative to the chosen root, where its two downward portions meet. Considering the sum of the deepest two branches at every node includes an optimal path. The optimal path need not pass through the root.
Each node’s height is computed once: O(n) time and O(h) stack space. A slower approach that recomputes subtree heights independently at every node can take O(n²) on a chain.
Instead of a nonlocal best value, a function could return (height,best_diameter_in_subtree) and combine both child summaries. That design makes all output explicit at the cost of a larger return contract. Both are valid; choose the version you can explain and verify clearly.
Analogy limit: node count, edge count, and weighted path cost are different quantities. The left_height + right_height expression works here because height counts nodes below the current node while diameter counts connecting edges.
Change one rule
Edges carry positive weights. Can counting nodes still identify the longest total-weight path?
Check the variation
No. Return the best downward weighted distance, including each connecting edge’s weight, and combine the best two weighted branches. The summary-and-candidate distinction remains useful even though the measured quantity changes.
Connect
LCA locates a meeting point for two specified nodes. Tree DP similarly separates what a parent needs from the whole subtree’s unconstrained optimum.