↓Skip to main content
  1. LeetCode/

LeetCode 834: Sum of Distances in Tree

·3 mins· ·
LeetCode Hard Dynamic-Programming Tree Depth-First-Search Graph Dp-on-Trees
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: hard First Attempt: 2026-10-31

  • Submissions: Wrong Answer → Accepted ×3

Approach
#

Running a BFS from every node is O(n^2), too slow for n up to 3 * 10^4. Rerooting DP needs only two passes:

  1. With 0 as the root, bottom-up:

    • count[v]: number of nodes in v’s subtree.
    • ans[v]: sum of distances from v to the nodes in its subtree. ans[p] += ans[v] + count[v], because every node in v’s subtree is one step farther from p than from v.
    • After this pass ans[0] is final.
  2. Top-down rerooting: moving the root from p to its child v, the count[v] nodes in v’s subtree get 1 closer and the other n - count[v] nodes get 1 farther:

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

With the BFS order order, iterating in reverse is bottom-up and forward is top-down, with no recursion (the tree can be a long chain).

My Attempts
#

  1. In both loops I wrote u where node was meant. u was left over from the graph-building loop, so Python raised nothing and kept using the last edge’s endpoint, and every answer was wrong: n = 2, edges = [[0,1]] returned [0,0] instead of [1,1]. The same version also had a p != 1 typo (should be -1) and left the root out of order.
  2. Fixing those passed. I rewrote it from scratch twice more the same day and both passed on the first try.

Solution
#

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):          # bottom-up
            p = parent[node]
            if p != -1:
                count[p] += count[node]
                ans[p] += ans[node] + count[node]

        for node in order:                    # top-down rerooting
            p = parent[node]
            if p != -1:
                ans[node] = ans[p] - count[node] + (n - count[node])
        return ans

Complexity
#

Time O(n), space O(n).

Mistakes to Avoid
#

  • Rerooting needs the final ans[p], so the second pass must go top-down (BFS order), not in reverse.
  • After the first pass only ans[0] is a full answer; the other ans[v] only cover their subtrees.
  • Watch loop variable names: in Python a loop variable still exists after its loop ends, so a typo silently uses a stale value.

Interview Explanation
#

I use rerooting DP. With 0 as the root I compute, bottom-up, each subtree’s size and the sum of distances from a node into its subtree, which makes ans[0] correct. Moving the root from a parent to a child brings the child’s subtree one step closer and everything else one step farther, so ans[v] = ans[p] - count[v] + n - count[v], applied top-down. Two passes, O(n) time.

Related

LeetCode 968: Binary Tree Cameras
·3 mins
LeetCode Hard Dynamic-Programming Tree Depth-First-Search Binary-Tree Dp-on-Trees
LeetCode 968 note: post-order greedy with three states per node: has a camera, covered, not covered; place a camera only when a child is uncovered, and add one if the root is left uncovered
LeetCode 124: Binary Tree Maximum Path Sum
·2 mins
LeetCode Hard Dynamic-Programming Tree Depth-First-Search Binary-Tree Dp-on-Trees
LeetCode 124 note: DFS returns the best downward chain and updates the answer with left chain + node + right chain at every node; drop negative chains
LeetCode 2858: Minimum Edge Reversals So Every Node Is Reachable
·2 mins
LeetCode Hard Dynamic-Programming Depth-First-Search Breadth-First-Search Graph
LeetCode 2858 note: rerooting DP: count the reversals needed with root 0, then moving the root to a child adds 1 if that edge pointed down and subtracts 1 if it pointed up
LeetCode 1372: Longest ZigZag Path in a Binary Tree
·2 mins
LeetCode Medium Dynamic-Programming Tree Depth-First-Search Binary-Tree Dp-on-Trees
LeetCode 1372 note: each node returns two values, the longest zigzag starting left and starting right; going left extends the left child’s start-right value
LeetCode 2973: Find Number of Coins to Place in Tree Nodes
·3 mins
LeetCode Hard Dynamic-Programming Tree-Dp Depth-First-Search Sorting Heap Tree
LeetCode 2973 note: the max product of three is either the three largest or the two smallest times the largest, so each subtree returns only its 2 smallest and 3 largest values, merged in post-order
LeetCode 1373: Maximum Sum BST in Binary Tree
·2 mins
LeetCode Hard Dynamic-Programming Tree-Dp Binary-Search-Tree Depth-First-Search Tree
LeetCode 1373 note: a post-order traversal returns (sum, min, max, is_bst); a node roots a BST when the left max < its value < the right min