↓快轉到主要內容
  1. LeetCode/

LeetCode 834: Sum of Distances in Tree

·2 分鐘· ·
LeetCode Hard Dynamic-Programming Tree Depth-First-Search Graph Dp-on-Trees
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: hard 第一次嘗試:2026-10-31

  • 提交紀錄:Wrong Answer → Accepted ×3

解題思路
#

對每個節點都跑一次 BFS 是 O(n^2),n 到 3 * 10^4 會超時。用換根 DP,兩次走訪就好:

  1. 以 0 為根,由下往上算:

    • count[v]:v 的子樹有幾個節點。
    • ans[v]:v 到它子樹裡所有節點的距離和。ans[p] += ans[v] + count[v],因為 v 子樹裡每個節點到 p 都比到 v 多 1。
    • 做完之後 ans[0] 就是正確答案。
  2. 由上往下換根:根從 p 移到小孩 v 時,v 子樹裡的 count[v] 個節點各近 1,其他 n - count[v] 個節點各遠 1:

    ans[v] = ans[p] - count[v] + (n - count[v])

用 BFS 得到的順序 order:反著走就是由下往上,正著走就是由上往下,不用遞迴(樹可能是一條長鏈)。

我的嘗試
#

  1. 兩個迴圈裡應該用 node 的地方寫成了 u。u 是前面建圖迴圈留下來的變數,Python 不會報錯,只會一直用最後一條邊的端點,答案全錯:n = 2, edges = [[0,1]] 回傳 [0,0],答案是 [1,1]。同一份還有 p != 1(應該是 -1)的筆誤,order 也漏了根。
  2. 修好就過了。之後同一天又從頭寫了兩次,都一次通過。

正確解法
#

class Solution:
    def sumOfDistancesInTree(self, n: int, edges: List[List[int]]) -> List[int]:
        graph = defaultdict(list)
        for u, v in edges:
            graph[u].append(v)
            graph[v].append(u)

        parent = [-1] * n
        seen = [False] * n
        seen[0] = True
        order = []
        queue = deque([0])
        while queue:
            node = queue.popleft()
            order.append(node)
            for nei in graph[node]:
                if not seen[nei]:
                    seen[nei] = True
                    parent[nei] = node
                    queue.append(nei)

        count = [1] * n
        ans = [0] * n
        for node in reversed(order):          # 由下往上
            p = parent[node]
            if p != -1:
                count[p] += count[node]
                ans[p] += ans[node] + count[node]

        for node in order:                    # 由上往下換根
            p = parent[node]
            if p != -1:
                ans[node] = ans[p] - count[node] + (n - count[node])
        return ans

複雜度
#

時間 O(n),空間 O(n)。

要特別避免的錯誤
#

  • 換根時要用 ans[p] 的最終值,所以第二次要由上往下走(BFS 順序),不能反著走。
  • 第一次走完只有 ans[0] 是完整答案,其他 ans[v] 只是子樹內的距離和。
  • 迴圈變數不要和外面的變數同名或打錯,Python 的迴圈變數離開迴圈後還在。

面試口說整理
#

我用換根 DP。先以 0 為根,由下往上算每個子樹的大小,和節點到子樹內所有點的距離和,這樣 ans[0] 就對了。根從父節點移到小孩時,小孩子樹裡的點各近 1,其他點各遠 1,所以 ans[v] = ans[p] - count[v] + n - count[v],由上往下推一次。兩次走訪,時間 O(n)。

相關文章

LeetCode 968: Binary Tree Cameras
·1 分鐘
LeetCode Hard Dynamic-Programming Tree Depth-First-Search Binary-Tree Dp-on-Trees
LeetCode 968 解題筆記:後序貪心,每個節點三種狀態:有相機、被覆蓋、沒被覆蓋;有小孩沒被覆蓋才放相機,最後根沒被覆蓋要補一台
LeetCode 124: Binary Tree Maximum Path Sum
·1 分鐘
LeetCode Hard Dynamic-Programming Tree Depth-First-Search Binary-Tree Dp-on-Trees
LeetCode 124 解題筆記:DFS 回傳往下的一條鏈,在每個節點用「左鏈 + 自己 + 右鏈」更新答案;負的鏈要丟掉
LeetCode 2858: Minimum Edge Reversals So Every Node Is Reachable
·1 分鐘
LeetCode Hard Dynamic-Programming Depth-First-Search Breadth-First-Search Graph
LeetCode 2858 解題筆記:換根 DP:先算以 0 為根要翻幾條邊,根移到小孩時,這條邊原本順向就 +1、逆向就 -1
LeetCode 1372: Longest ZigZag Path in a Binary Tree
·1 分鐘
LeetCode Medium Dynamic-Programming Tree Depth-First-Search Binary-Tree Dp-on-Trees
LeetCode 1372 解題筆記:每個節點回傳兩個值:從這裡先往左、先往右的最長 zigzag;往左走接的是左小孩「先往右」的值
LeetCode 2973: Find Number of Coins to Place in Tree Nodes
·2 分鐘
LeetCode Hard Dynamic-Programming Tree-Dp Depth-First-Search Sorting Heap Tree
LeetCode 2973 解題筆記:三個數的最大乘積只可能是「最大的三個」或「最小的兩個 × 最大的一個」;每個子樹只回傳最小 2 個和最大 3 個,後序合併
LeetCode 1373: Maximum Sum BST in Binary Tree
·1 分鐘
LeetCode Hard Dynamic-Programming Tree-Dp Binary-Search-Tree Depth-First-Search Tree
LeetCode 1373 解題筆記:後序遍歷回傳 (總和, 最小值, 最大值, 是不是 BST);左子樹的最大值 < 自己 < 右子樹的最小值才是 BST