Binary Tree - DFS · Medium
LeetCode 1372: Longest ZigZag Path in a Binary Tree — solution
Solve LeetCode 1372 with a DFS that tracks two lengths per node — the zigzag arriving as a left child and as a right child — O(n) time, O(h) space.
Problem in plain words
A zigzag path starts at any node, takes one step to a child (left or right), and then must keep alternating direction: left, right, left, … or right, left, right, …. Its length is the number of steps (edges). Return the length of the longest zigzag path anywhere in the tree. A single node has length 0.
Example: root A has a right child B, B has a left child C, and C has a right child D. The path A → B → C → D goes right, left, right, so its length is 3.
Intuition
For each node, remember two numbers: l, the length of the longest zigzag that ends here having just stepped left into this node, and r, the same for a step right into it. If you go to the left child, you are stepping left, so the zigzag can continue only if the previous step was right: the child's l becomes r + 1, and its r resets to 0 (a fresh path could start by going right from it). Symmetrically, the right child gets r = l + 1 and l = 0. The answer is the largest value seen.
Approach
- Start at the root with
l = 0andr = 0. - At each node, update
best = max(best, l, r). - Visit the left child with
(r + 1, 0). - Visit the right child with
(0, l + 1). - Return
bestafter the whole tree is explored.
Dry run
| Node | Reached by | l | r | best |
|---|---|---|---|---|
| A | start | 0 | 0 | 0 |
| B | right of A | 0 | 1 | 1 |
| C | left of B | 2 | 0 | 2 |
| D | right of C | 0 | 3 | 3 |
Java solution
class Solution {
private int best = 0;
public int longestZigZag(TreeNode root) {
dfs(root, 0, 0);
return best;
}
// left = zigzag length ending here with a step to the left
// right = zigzag length ending here with a step to the right
private void dfs(TreeNode node, int left, int right) {
if (node == null) {
return;
}
best = Math.max(best, Math.max(left, right));
dfs(node.left, right + 1, 0);
dfs(node.right, 0, left + 1);
}
}Python solution
class Solution:
def longestZigZag(self, root: Optional[TreeNode]) -> int:
best = 0
stack = [(root, 0, 0)]
while stack:
node, left_len, right_len = stack.pop()
best = max(best, left_len, right_len)
if node.left:
stack.append((node.left, right_len + 1, 0))
if node.right:
stack.append((node.right, 0, left_len + 1))
return bestComplexity
| Measure | Cost | Why |
|---|---|---|
| Time | O(n) | Each node is visited once with constant work. |
| Space | O(h) | The recursion or explicit stack depth is bounded by the tree height (the stack version may hold up to O(n) entries in the worst case). |
Edge cases and common mistakes
- Counting nodes instead of edges — the length is the number of steps, so a lone node is
0. - Mixing up the two slots — stepping left continues a path whose last step was right, so the left child gets
r + 1, notl + 1. The other slot becomes0, meaning a new zigzag can start at the child. - Starting a fresh DFS from every node — that is O(n²). The two-length state lets every node be handled once.
- Recursion depth in Python — with up to 5·10^4 nodes, a skewed tree can exceed the default recursion limit; the iterative stack avoids that.
›Can I do it bottom-up instead?
Yes. Have each call return a pair (longest path going left from this node, longest going right). Then goLeft = 1 + child.left's goRight and so on, updating a global best. It is the same O(n) idea viewed from the children.
