The O(n) Club: Sum of Distances in Tree — Two DFSes, No Tears

The O(n) Club: Sum of Distances in Tree — Two DFSes, No Tears

⚡ TL;DR

Want to sum distances from every node to every other node? Don’t write a BFS-for-every-node death loop unless you’re benchmarking fans. Instead: two DFS passes, one for tallying up the minions, one for updating as you re-root. Short on drama, big on results:

// Java post-order DFS: gather subtree sums and sizes
private void postOrder(int node, int parent) {
    for (int child : tree[node]) if (child != parent) {
        postOrder(child, node);
        count[node] += count[child];
        res[node] += res[child] + count[child];
    }
}

🧠 How Devs Usually Mess This Up

New hire energy: “Let’s do a BFS/DFS from every node!” — lovely, unless n is >10, and you suddenly own a cryptocurrency heat generator. That’s O(n²) and terrible. The MVP failure mode here? People confuse subtree size (count[node]) with depth. Remember: count[node] is how big your cult following is, not how famous you are. Also, don’t recalculate answers for each root from scratch — tree DP is all about recycling.

🔍 What’s Actually Going On

This algorithm is what happens when dynamic programming and accounting have a baby. Imagine your company as a tree: you, as CEO, want to know your ‘distance’ to every employee. But you’re lazy. So you make each manager total up their subordinates’ scores and pass it up. Enter post-order DFS (bottom-up), where every node sums up its descendants.

Then, the magic: re-rooting! Pretend you make each child a CEO for the day. Using a simple trick, you give them their score in O(1), piggybacking off parent’s answer, using the formula:

ans[child] = ans[parent] - count[child] + (n - count[child]);

It’s corporate ladder climbing, without the performance reviews.

🛠️ PseudoCode

  • Build the tree as an adjacency list in Java:
    for (int[] e : edges) {
        tree[e[0]].add(e[1]);
        tree[e[1]].add(e[0]);
    }

    If you don’t, you get an O(n²) LinkedList party. No one wants that.

  • First DFS (post-order):
    postOrder(node, parent):
      count[node] = 1;
      for each child != parent:
        postOrder(child, node)
        count[node] += count[child]
        res[node] += res[child] + count[child]
    

    This sweeps up all the kids’ answers. Leaves start with count=1, res=0.

  • Second DFS (pre-order):
    preOrder(node, parent):
      for each child != parent:
        res[child] = res[node] - count[child] + (n - count[child])
        preOrder(child, node)
    

    Suddenly, each child knows their sum, using their parent’s results like a true social climber.

  • Return res[] — now res[i] is the answer for each node.

💻 The Code

class Solution {
    int[] res, count;
    List
<integer>[] tree;
    int n;
    public int[] sumOfDistancesInTree(int N, int[][] edges) {
        n = N;
        tree = new List[N];
        res = new int[N];
        count = new int[N];
        for (int i = 0; i < N; i++) tree[i] = new ArrayList<>();
        for (int[] e : edges) {
            tree[e[0]].add(e[1]);
            tree[e[1]].add(e[0]);
        }
        dfsPost(0, -1);
        dfsPre(0, -1);
        return res;
    }
    private void dfsPost(int node, int parent) {
        count[node] = 1;
        for (int child : tree[node]) {
            if (child == parent) continue;
            dfsPost(child, node);
            count[node] += count[child];
            res[node] += res[child] + count[child];
        }
    }
    private void dfsPre(int node, int parent) {
        for (int child : tree[node]) {
            if (child == parent) continue;
            res[child] = res[node] - count[child] + (n - count[child]);
            dfsPre(child, node);
        }
    }
}
</integer>

⚠️ Pitfalls, Traps & Runtime Smacks

  • DFS Parent Check: If you forget it, enjoy that stack overflow.
  • Subtree Size vs. Depth: Don’t mix these or you’ll have a philosophical crisis and a wrong answer.
  • Edge Cases: Handle single-node “trees” and stars (one hub, all leaf workers). If you crash on these, the LeetCode bot will snark at you.
  • Space: O(n) for arrays and lists; don’t pull out a HashMap unless you miss slow code.
  • Time: The two DFSes are O(n). The only thing quadratic should be your caffeine intake.

🧠 Interviewer Brain-Tattoo

“Never BFS from every node in a tree unless you want an angry reviewer. Re-root, reuse, get O(n), go home early.”

Previous Article

The O(n) Club: Reverse Pairs & That Merge Sort Plot Twist

Next Article

The O(n) Club: Remove All Adjacent Duplicates in String II—Stack Attack Edition