Number of Connected Components in an Undirected Graph

MediumGraphs · Union-Find · DFS🧩 Union-FindLeetCode #323 ↗Updated

Problem

You have n nodes labelled 0..n-1 and a list of undirected edges, where [a, b] joins nodes a and b. Return how many connected components the graph has — i.e. how many separate “islands” of nodes remain, counting isolated nodes as their own island.
Inputn=5, edges=[[0,1],[1,2],[3,4]]Output2
Inputn=5, edges=[[0,1],[1,2],[2,3],[3,4]]Output1
Inputn=4, edges=[]Output4

1 ≤ n ≤ 2000  ·  0 ≤ edges.length ≤ 5000  ·  a ≠ b  ·  no repeated edges

Try it yourself

Java
class Solution {
    public int countComponents(int n, int[][] edges) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
Start with n separate components. Every edge that joins two different components merges them, so the answer is n minus the number of successful merges — exactly what Union-Find counts.
PatternUnion-Find

Instinct Items get grouped by "connected", "same as" or "shares a" links and you keep asking which group something is in: merge sets with Union-Find.

Memory hack Find your boss, merge the bosses; squash the chain (path compression) and hang the short tree under the tall one (rank).

Open the Union-Find guide →

Approaches

Brute ForceLabel Propagation Until Stable

Time O(V · E)Space O(V)

Give every node its own label. Repeatedly sweep the edge list and let both ends adopt the smaller label. The minimum label spreads one hop per sweep, so after at most V sweeps every component carries its smallest node id; count nodes whose label is still their own id.

Java
public int countComponents(int n, int[][] edges) {
    int[] label = new int[n];
    for (int i = 0; i < n; i++) label[i] = i;
    boolean changed = true;
    while (changed) {
        changed = false;
        for (int[] e : edges) {
            int m = Math.min(label[e[0]], label[e[1]]);
            if (label[e[0]] != m || label[e[1]] != m) {
                label[e[0]] = m;
                label[e[1]] = m;
                changed = true;
            }
        }
    }
    // Each component ends up labelled with its smallest node id
    int count = 0;
    for (int i = 0; i < n; i++) if (label[i] == i) count++;
    return count;
}

No graph structure needed, but up to V full passes over the edges.

At a glance

LevelApproachTimeSpace
Brute ForceLabel Propagation Until StableO(V · E)O(V)
BetterAdjacency List + DFS Flood FillO(V + E)O(V + E)
OptimalUnion-Find (Path Compression + Union by Size)O(V + E · α(V))O(V)
Common pitfalls
  • Forgetting isolated nodes — a node with no edges is still one component.
  • Decrementing the count on every edge — edges that close a cycle must not count.
  • Adding only one direction to the adjacency list — the graph is undirected.
Interview tips
  • Mention both DFS and Union-Find; pick Union-Find if edges could arrive incrementally.
  • Explain why path compression + union by size gives near-constant amortised cost.
  • Use an iterative stack for DFS to avoid deep recursion on a long chain.
Pattern
Union-Find / flood fill → counting or merging groups of connected items.
My notes saved in this browser