Number of Connected Components in an Undirected Graph
Union-find each edge; count distinct roots.
3 min read
union-find graph
Problem#
Given n nodes and an edge list, return the number of connected components.
Examples#
n=5, edges=[[0,1],[1,2],[3,4]]→2.n=5, edges=[[0,1],[1,2],[2,3],[3,4]]→1.
Constraints#
1 <= n <= 2000.
Approach#
Union-find. Initialize n components; union both endpoints of each edge; return the number of nodes still pointing to themselves as root.
Solution#
class Solution { vector<int> par; int find(int x) { return par[x] == x ? x : par[x] = find(par[x]); }public: int countComponents(int n, vector<vector<int>>& edges) { par.resize(n); iota(par.begin(), par.end(), 0); int comps = n; for (auto& e : edges) { int a = find(e[0]), b = find(e[1]); if (a != b) { par[a] = b; --comps; } } return comps; }};func countComponents(n int, edges [][]int) int { par := make([]int, n) for i := range par { par[i] = i } var find func(int) int find = func(x int) int { if par[x] != x { par[x] = find(par[x]) } return par[x] } comps := n for _, e := range edges { a, b := find(e[0]), find(e[1]) if a != b { par[a] = b comps-- } } return comps}class Solution: def countComponents(self, n: int, edges: List[List[int]]) -> int: par = list(range(n))
def find(x: int) -> int: while par[x] != x: par[x] = par[par[x]] x = par[x] return x
comps = n for a, b in edges: ra, rb = find(a), find(b) if ra != rb: par[ra] = rb comps -= 1 return compsfunction countComponents(n, edges) { const par = Array.from({ length: n }, (_, i) => i); const find = (x) => { while (par[x] !== x) { par[x] = par[par[x]]; x = par[x]; } return x; }; let comps = n; for (const [a, b] of edges) { const ra = find(a), rb = find(b); if (ra !== rb) { par[ra] = rb; comps--; } } return comps;}class Solution { private int[] par;
public int countComponents(int n, int[][] edges) { par = new int[n]; for (int i = 0; i < n; i++) par[i] = i; int comps = n; for (int[] e : edges) { int a = find(e[0]), b = find(e[1]); if (a != b) { par[a] = b; comps--; } } return comps; }
private int find(int x) { while (par[x] != x) { par[x] = par[par[x]]; x = par[x]; } return x; }}function countComponents(n: number, edges: number[][]): number { const par: number[] = Array.from({ length: n }, (_, i) => i); const find = (x: number): number => { while (par[x] !== x) { par[x] = par[par[x]]; x = par[x]; } return x; }; let comps = n; for (const [a, b] of edges) { const ra = find(a), rb = find(b); if (ra !== rb) { par[ra] = rb; comps--; } } return comps;}Editorial#
DSU runs in near-linear time with path compression alone. The component count decreases by 1 on every successful union; starting at n and decrementing is cleaner than counting roots at the end.
Complexity#
- Time: ~
O(n + e). - Space:
O(n).
Concept revision#
Related#