Longest ZigZag Path in a Binary Tree

題目描述

給定一棵二元樹的根節點 root,回傳最長 ZigZag 路徑的長度。ZigZag 路徑定義為:從任意節點開始,交替走左右方向。路徑長度等於邊數。

輸入:         1
             / \
            1   1
             \   \
              1   1
             / \
            1   1
               \
                1
輸出: 3
解釋: 右→左→右(3 條邊)

解題思路

1

DFS 帶方向資訊

dfs(node, left, right) 中 left 代表最後一步走左到此的 ZigZag 長度,right 同理

2

走左子樹

呼叫 dfs(node.left, right+1, 0):延續上步走右的長度加 1(交替),同時重置 right 為 0

3

走右子樹

呼叫 dfs(node.right, 0, left+1):延續上步走左的長度加 1(交替),同時重置 left 為 0

4

方向不對則重置

傳入 0 代表該方向的 ZigZag 從頭開始 — 例如連續走兩次左就不是 ZigZag

5

更新全域最大值

每個節點執行 maxLen = max(maxLen, left, right) 追蹤全域最優解

程式碼

C#

csharp
public class Solution {
    private int maxLen = 0;
 
    public int LongestZigZag(TreeNode root) {
        Dfs(root, 0, 0);
        return maxLen;
    }
 
    // left: 以此節點為終點、最後一步走左的 ZigZag 長度
    // right: 以此節點為終點、最後一步走右的 ZigZag 長度
    private void Dfs(TreeNode node, int left, int right) {
        if (node == null) return;
 
        maxLen = Math.Max(maxLen, Math.Max(left, right));
 
        // 往左走:延續 right+1(上步走右,這步走左 = zigzag)
        //         重置 left 為 0(因為往左走時,若下一步再走左就斷了)
        Dfs(node.left, right + 1, 0);
 
        // 往右走:延續 left+1,重置 right
        Dfs(node.right, 0, left + 1);
    }
}

TypeScript

typescript
function longestZigZag(root: TreeNode | null): number {
    let maxLen = 0;
 
    function dfs(node: TreeNode | null, left: number, right: number): void {
        if (!node) return;
 
        maxLen = Math.max(maxLen, left, right);
 
        dfs(node.left, right + 1, 0);  // 走左:延續上步走右的長度
        dfs(node.right, 0, left + 1);  // 走右:延續上步走左的長度
    }
 
    dfs(root, 0, 0);
    return maxLen;
}

Python

python
def longestZigZag(root: Optional[TreeNode]) -> int:
    max_len = 0
 
    def dfs(node, left, right):
        nonlocal max_len
        if not node:
            return
 
        max_len = max(max_len, left, right)
 
        dfs(node.left, right + 1, 0)   # 走左:延續上步走右的長度
        dfs(node.right, 0, left + 1)   # 走右:延續上步走左的長度
 
    dfs(root, 0, 0)
    return max_len

複雜度分析

TimeSpace
本解法O(n)O(h)

Time O(n) 是因為每個節點恰好被 DFS 訪問一次,每次做常數操作(比較和更新 maxLen)。Space O(h) 是遞迴 call stack 深度,h 為樹高。

邊界情況

圖解

root(0,0)
走左
左子(1,0)
走右 zigzag
右子(0,2)
走左 zigzag
左子(3,0)
走右 zigzag
右子(0,1)

圖表展示了 ZigZag 長度的傳遞方式:每次交替方向時長度加 1,方向不交替時重置為 0。走左時繼承 right+1(因為是上一步走右的延續),走右時繼承 left+1。

進階觀點

💡面試追問

Q: 為什麼用兩個參數 left/right 而不是一個方向標記? A: 每個節點可能同時是兩條 ZigZag 路徑的終點 — 一條最後一步走左到此、一條最後一步走右到此。用兩個參數分別追蹤,才能在往子樹走時正確選擇延續哪條路徑。只用一個方向標記會丟失另一條路徑的資訊。

Q: 為什麼每個節點都要更新 maxLen 而不只在葉子更新? A: ZigZag 路徑不一定終止在葉子。例如某個節點只有左子樹,從右邊來的 ZigZag 無法繼續走右延續,但這條 ZigZag 的長度可能已是全域最大。

變體題:LC 543 Diameter of Binary Tree(最長路徑,不限方向交替)。

理解測驗

🤔 走到左子節點時,為什麼 right 參數傳 0?

🤔 一棵只有右子鏈的樹(1→2→3→4),最長 ZigZag 長度是多少?

你可能也想看

437. Path Sum III236. Lowest Common Ancestor of a Binary Tree

按 ← → 鍵切換課程