Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
A centroid of a tree is a node whose removal leaves every remaining component with at most n/2 nodes. Compute subtree sizes with one DFS, then a node is a centroid iff its largest 'piece' — the bigger of (its heaviest child subtree) and (n minus its own subtree, the part above it) — is ≤ ⌊n/2⌋. A tree has one centroid, or two adjacent centroids when n is even. Finding it is O(n).
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you compute subtree sizes correctly and — the real test — remember that removing a node also creates the component ABOVE it of size n − size[node], not just the child subtrees.
Where candidates slip
Only checking child subtree sizes and ignoring the n − size[node] part above the node, or confusing the centroid (balances component sizes) with the center (minimizes height).
How to stand out
Define the centroid precisely, derive the ≤ n/2 test from the size DFS, explain the 1-or-2 centroid fact, and note the O(n) 'walk toward the heavy child' method plus its role in centroid decomposition.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachExplore the full treeCollapse the tree
How to read it:Removing node X creates one component per child subtree plus the 'rest above' of size n − size[X]. The centroid keeps all pieces ≤ n/2.
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Brute Force — Remove Each Node, Measure the Pieces
1Hint 1Explore hintHide hint
For each candidate node, imagine deleting it and run a BFS/DFS over the rest to measure every resulting component.
2Hint 2Explore hintHide hint
If the largest component is ≤ n/2, the candidate is a centroid.
3Hint 3Explore hintHide hint
Each test is an O(n) traversal and there are n candidates → O(n²). Correct, but it screams 'precompute the sizes once'.
A · Core idea
The definition is constructive, so the brute force just follows it.
For each candidate. Pretend to delete the node, then traverse the remaining forest to find the size of each connected component.
Test the balance. If the maximum component size is at most ⌊n/2⌋, the candidate qualifies as a centroid; otherwise move on.
Why it is correct. It literally checks the centroid condition for every node, so it cannot be fooled.
Why it is slow. Each candidate costs an O(n) traversal, and there are n of them — O(n²). The redundancy is that every traversal recomputes the same subtree sizes. Compute those sizes once with a single DFS and each candidate's pieces can be read off in O(1): the child subtree sizes are stored, and the piece above is n − size[node].
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
path 0-1-2-3 (n=4); test each noderemove 0
component {1,2,3} size 3
3 > 2 → not centroid1 (and 2)C · Code with teaching comments
Reference implementation previewimport java.util.*; class BruteForceCentroid { int findCentroid(int n, int[][] edges) { List<List<Integer>> adj = new ArrayList<>();Explore the full codeHide the full code
D · Why it works and complexityO(n²) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
Doing the deletion explicitly reveals the components you must measure — including the one above the node. The optimization is purely that those component sizes are all derivable from a single subtree-size DFS, so the n repeated traversals collapse into one.
ComplexityO(n²) time, O(n) space — Removing a node and measuring components is an O(n) traversal; repeating for all n candidates gives O(n²). Fine for small n, too slow at 2×10⁵.
E · Edge cases and pitfalls3Forgetting that deleting an internal node creates a component above it as well as below.Explore edge casesHide edge cases
Pitfalls
- Forgetting that deleting an internal node creates a component above it as well as below.
- Recomputing component sizes for every candidate — the redundancy the size DFS removes.
- Using n/2 with the wrong rounding — use ⌊n/2⌋ consistently.
Approach 2 of 2 · Optimal
Subtree-Size DFS — Single Pass (Optimal)
1Hint 1Explore hintHide hint
Root the tree anywhere and compute size[node] = 1 + sum of children's sizes with one DFS.
2Hint 2Explore hintHide hint
When you remove a node, the pieces are its child subtrees (sizes already known) plus the part above it, whose size is n − size[node].
3Hint 3Explore hintHide hint
A node is a centroid iff the maximum of those pieces is ≤ n/2. Check every node in a second linear scan (or fold it into the DFS).
A · Core idea
Compute the structure once, then read off the answer.
Step 1 — subtree sizes. Root the tree at any node (say 0) and compute size[node] = 1 + Σ size[child] with a single post-order DFS. size[node] counts the node and everything below it in this rooting.
Step 2 — the pieces created by removal. Deleting node disconnects the tree into:
- one component per child, of size
size[child], and - the component above
node— everything not innode's subtree — of sizen − size[node].
The largest piece for node is therefore max( max over children size[child], n − size[node] ). The second term is the one candidates forget; it is exactly the rest of the tree hanging above the node through its parent.
Step 3 — the centroid test. node is a centroid iff that largest piece is ≤ ⌊n/2⌋. Scan all nodes and return any that pass. Because the sizes are precomputed, each node's check is O(deg), so the whole scan is O(n).
Why a centroid always exists, and why ≤ n/2. Start anywhere and repeatedly move to the neighbor whose component (after cutting the edge you came from) exceeds n/2. Each move strictly decreases the size of the heaviest piece, so the walk terminates — at a node where no piece exceeds n/2, the centroid. That same walk is an alternative O(n) algorithm: from the root, keep stepping into the child whose subtree size > n/2 until none qualifies.
Why one or two centroids. If some node has a child subtree of exactly n/2 (only possible when n is even), then both that node and that child satisfy the ≤ n/2 test, and they are adjacent. Otherwise the centroid is unique. There can never be three, because a third would force a piece larger than n/2 somewhere.
Centroid vs center. The centroid balances sizes (this problem). The center minimizes height (tree radius) and is found by repeatedly removing all current leaves until one or two nodes remain. They sometimes coincide but are different in general — naming the right one is part of the interview.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
star: 0 connected to 1,2,3,4 (n=5), rooted at 0Array state
sizes
size[0]=5, size[1]=size[2]=size[3]=size[4]=1
0C · Code with teaching comments
D · Why it works and complexityO(n) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
Everything hinges on a single accounting identity: removing a node leaves child subtrees you already measured plus a top piece of size n − size[node]. Once you internalize that the 'rest above' is just n minus the subtree, the centroid test is a one-line max comparison, and the whole problem is one DFS.
ComplexityO(n) time, O(n) space — One DFS computes all subtree sizes in O(n). A second O(n) scan evaluates each node's largest piece in O(deg) using stored sizes, summing to O(n). Total O(n) time, O(n) space for sizes and the stack.
E · Edge cases and pitfalls7n = 1 — Single node is its own centroid; handled before the DFS.Explore edge casesHide edge cases
Edge cases handled
n = 1Single node is its own centroid; handled before the DFS.n = 2 (one edge)Both nodes are centroids: removing either leaves one node (size 1 ≤ 1). Two adjacent centroids — the even-n case.perfectly balanced even tree across one edgeTwo adjacent centroids, each with a child subtree of exactly n/2; the scan returns the first one found.
Pitfalls
- Checking only child subtrees and ignoring the n − size[node] piece above the node.
- Confusing the centroid (balances sizes) with the center (minimizes height).
- Recursive size DFS on a chain of 2×10⁵ nodes — stack overflow; use an explicit stack.
- Rounding n/2 inconsistently — use integer ⌊n/2⌋ throughout.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewimport java.util.*; class Centroid { int findCentroid(int n, int[][] edges) { if (n == 1) return 0;Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Forgetting the piece above the node
Removing an internal node creates the child-subtree pieces AND the whole rest of the tree above it. That upper piece has size n − size[node]; skip it and almost every node looks like a centroid.
Explore the code comparisonHide the code comparison
Forgetting the piece above the node
Removing an internal node creates the child-subtree pieces AND the whole rest of the tree above it. That upper piece has size n − size[node]; skip it and almost every node looks like a centroid.
Don't write this
largest = 0
for c in adj[node]:
if c != parent[node]:
largest = max(largest, size[c]) # missing the upward piece
if largest <= n // 2:
return nodeWrite this instead
largest = n - size[node] # the part above node
for c in adj[node]:
if c != parent[node]:
largest = max(largest, size[c])
if largest <= n // 2:
return node2Centroid vs center confusion
The center minimizes tree height (found by peeling leaves) while the centroid balances component sizes. They can be different nodes; solving the wrong one fails the test even with correct code.
Explore the code comparisonHide the code comparison
Centroid vs center confusion
The center minimizes tree height (found by peeling leaves) while the centroid balances component sizes. They can be different nodes; solving the wrong one fails the test even with correct code.
Don't write this
# Peeling leaves finds the CENTER, not the centroid
while len(remaining) > 2:
remove_all_current_leaves()Write this instead
# Centroid: balance sizes
largest = max(n - size[node], max((size[c] for c in children), default=0))
if largest <= n // 2:
return node3Recursive size DFS overflow
A chain of 2×10⁵ nodes recurses 2×10⁵ deep, overflowing the default call stack in both Java and Python. Compute subtree sizes with an explicit stack and a reverse-order pass.
Explore the code comparisonHide the code comparison
Recursive size DFS overflow
A chain of 2×10⁵ nodes recurses 2×10⁵ deep, overflowing the default call stack in both Java and Python. Compute subtree sizes with an explicit stack and a reverse-order pass.
Don't write this
def dfs(node, parent):
size[node] = 1
for c in adj[node]:
if c != parent:
dfs(c, node) # depth up to n
size[node] += size[c]Write this instead
stack = [root]; order = []
while stack:
node = stack.pop(); order.append(node)
for c in adj[node]:
if c != parent[node]: parent[c] = node; stack.append(c)
for node in reversed(order):
size[node] = 1 + sum(size[c] for c in adj[node] if c != parent[node])Revise
Carry the pattern into the interview
Pattern to remember
Subtree-size DFS, then test max(child subtrees, rest-of-tree) ≤ n/2
Code pattern to memorize
size[node] = 1 + Σ size[child]
for each node:
biggest = max over children of size[child]
biggest = max(biggest, n - size[node]) # the part above node
if biggest <= n // 2: node is a centroidRules to remember
- 1The 'piece above' a node has size n − size[node] — do not forget it; it is the most-missed component.
- 2A node is a centroid iff its largest component after removal ≤ ⌊n/2⌋.
- 3Every tree has 1 or 2 centroids; 2 (adjacent) happen exactly when n is even and the tree is balanced across one edge.
- 4Centroid sizes are computed from any root — rooting does not change the answer, only how you phrase 'above'.
- 5Walking from any start toward the heaviest neighbor whose subtree > n/2 reaches a centroid in O(n).
Use this pattern when
- Balancing a tree for divide-and-conquer (centroid decomposition)
- Bounding recursion depth: rooting at the centroid limits component size to n/2
- Problems over all paths in a tree solved by splitting at a balanced node
- Minimizing the maximum subtree size after removing one node
Choose another pattern when
- You need the node minimizing total distance to all others → that is also the centroid, but state it as the 1-median; same node, different framing
- You need the center (minimizing eccentricity / tree radius) → that is a different node found by peeling leaves (BFS)
- Weighted 'balance' by edge length, not node count → adapt the size definition accordingly
- Graph has cycles → 'centroid' is undefined; this relies on the tree structure
Interview takeaway
The centroid is the tree's balance point: remove it and no leftover piece exceeds half the tree. One subtree-size DFS plus remembering the 'piece above' (n − size) finds it in O(n), and it is the anchor that makes centroid decomposition's O(n log n) divide-and-conquer work.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternCentroid of a tree: compute subtree sizes with one DFS, then a node is a centroid iff its largest piece after removal — max(heaviest child subtree, n − size[node]) — is ≤ ⌊n/2⌋. There are one or two (adjacent) centroids, found in O(n). It is the balance point that anchors centroid decomposition.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Centroid DecompositionComing soonRecursively make the centroid the root of its component; depth is O(log n), enabling divide-and-conquer over all paths.
- Minimum Height TreesComing soonFinds the tree CENTER (1 or 2 nodes) by peeling leaves — contrast with the centroid here.
- Sum of Distances in TreeComing soonRe-rooting DP; the node minimizing total distance is the centroid (1-median) view of balance.
- Heavy-Light DecompositionAnother size-driven decomposition; the heavy-child idea mirrors the largest-subtree reasoning used here.