GRAPHS / ALGORITHM BRIEF

Union Find

Union Find (disjoint set union, DSU) tracks which elements belong to the same group as groups merge.

IntermediatePhase 05 / Topic 5 of 10Mental modelComplexityEdge cases
01

Overview

Union Find (disjoint set union, DSU) tracks which elements belong to the same group as groups merge. It supports two operations: find(x) returns the representative (root) of x's group, and union(a, b) merges the groups of a and b. With path compression and union by rank, both run in nearly O(1) amortized time.

It shines when connections arrive over time and you repeatedly ask 'are these connected?' or 'how many groups are there?' It is also the core of Kruskal's minimum spanning tree algorithm and a clean way to detect cycles in undirected graphs.

Merging clubs with a president each

Every club has a president. To know if two people are in the same club, ask each for their president. When two clubs merge, one president reports to the other. Path compression is everyone learning the top president's name directly so future questions are instant.

02

When to use it

  • Dynamic connectivity: edges are added and you query whether two nodes are connected.
  • Counting connected components as edges arrive.
  • Detecting a cycle when adding undirected edges (redundant connection).
  • Grouping equivalent items: accounts with shared emails, similar strings, equations.
  • Kruskal's minimum spanning tree.
03

Problem patterns it solves

Count components

Recognize it when: number of provinces, groups, or islands after unions.

  • 547. Number of Provinces
  • 323. Number of Connected Components
  • 305. Number of Islands II
Cycle on edge addition

Recognize it when: the edge that connects two already-connected nodes.

  • 684. Redundant Connection
  • 261. Graph Valid Tree
  • 685. Redundant Connection II
Group by equivalence

Recognize it when: merge items that share an attribute.

  • 721. Accounts Merge
  • 839. Similar String Groups
  • 990. Satisfiability of Equality Equations
  • 1202. Smallest String With Swaps
Minimum spanning tree

Recognize it when: connect everything with minimum total cost.

  • 1584. Min Cost to Connect All Points
  • 1135. Connecting Cities With Minimum Cost
Offline queries sorted by threshold

Recognize it when: answer 'connected with limit x' queries by sorting edges and queries.

  • 1697. Checking Existence of Edge Length Limited Paths
  • 1631. Path With Minimum Effort (DSU variant)
04

Where it is used in real software

Network connectivity

Determining whether two machines can communicate as links come online, and counting isolated network segments.

Image segmentation

Connected-component labeling merges neighboring pixels with similar colors into regions.

Identity resolution

Merging user records that share an email, phone, or device into a single customer profile.

Compilers

Type inference (unification) merges type variables that must be equal, using union-find.

05

Key terms

parent[x]
The node x points to; a root points to itself.
find(x)
Follow parents to the root.
Path compression
During find, point every visited node directly at the root.
Union by rank / size
Attach the smaller tree under the larger to keep trees shallow.
Inverse Ackermann alpha(n)
The amortized cost per operation; at most 4 for any practical n.
06

How it works, step by step

  1. 1
    Initialize

    parent[i] = i and size[i] = 1 for every element. components = n.

  2. 2
    find(x)

    If parent[x] !== x, set parent[x] = find(parent[x]) (path compression) and return it.

  3. 3
    union(a, b)

    Find both roots. If equal, they are already connected (a cycle for edges).

  4. 4
    Attach smaller under larger

    parent[smallRoot] = bigRoot; size[bigRoot] += size[smallRoot]; components--.

  5. 5
    connected(a, b)

    find(a) === find(b).

07

684. Redundant Connection

edges = [[1,2], [1,3], [2,3]]

Step 1 / 3
Edgefind(u)find(v)Same root?Action
[1, 2]12nounion: parent[2] = 1
[1, 3]13nounion: parent[3] = 1
[2, 3]11yesredundant edge: return [2, 3]

NOWEdge: [1, 2] | find(u): 1 | find(v): 2 | Same root?: no | Action: union: parent[2] = 1

When both endpoints already share a root, the edge closes a cycle. Each check is nearly O(1), so processing all edges is almost linear.

08

Implementation

class UnionFind {  constructor(n) {    this.parent = Array.from({ length: n }, (_, i) => i);    this.size = new Array(n).fill(1);    this.components = n;  }   find(x) {    while (this.parent[x] !== x) {      this.parent[x] = this.parent[this.parent[x]]; // path halving      x = this.parent[x];    }    return x;  }   union(a, b) {    let ra = this.find(a), rb = this.find(b);    if (ra === rb) return false; // already connected    if (this.size[ra] < this.size[rb]) [ra, rb] = [rb, ra];    this.parent[rb] = ra;    this.size[ra] += this.size[rb];    this.components--;    return true;  }   connected(a, b) { return this.find(a) === this.find(b); }} function findRedundantConnection(edges) {  const uf = new UnionFind(edges.length + 1);  for (const [u, v] of edges) if (!uf.union(u, v)) return [u, v];  return [];} // 990. Satisfiability of Equality Equationsfunction equationsPossible(equations) {  const uf = new UnionFind(26);  const id = (ch) => ch.charCodeAt(0) - 97;  for (const e of equations) if (e[1] === "=") uf.union(id(e[0]), id(e[3]));  return equations.every((e) => e[1] === "=" || !uf.connected(id(e[0]), id(e[3])));}
09

Complexity and performance

find / unionO(alpha(n))

Nearly constant with both optimizations.

Without optimizationsO(n)

Trees can become chains.

m operationsO(m alpha(n))

Effectively linear.

SpaceO(n)

parent and rank arrays.

10

Trade-offs

Union Find vs BFS / DFS

For a static graph, BFS or DFS counts components just as well. Union Find wins when edges arrive incrementally and queries are interleaved.

No deletions

Standard DSU cannot split groups. If edges are removed, process operations in reverse (adding edges) or use other structures.

11

Variants and related techniques

Weighted Union Find

Store a ratio or offset to the parent to answer equations like a / b = 2 (Evaluate Division).

Union Find with rollback

Skip path compression and keep a stack of changes so unions can be undone, used in offline algorithms.

Map-based DSU

Use a Map for parent when elements are strings or sparse large numbers.

12

Common mistakes

  • Comparing parent[a] === parent[b] instead of roots.

    Fix: Always compare find(a) and find(b).

  • Forgetting path compression.

    Fix: Without it, chains make find O(n) and solutions time out.

  • Off-by-one for 1-indexed nodes.

    Fix: Allocate n + 1 slots.

13

Interview questions

What do path compression and union by rank achieve?

Path compression flattens trees during find; union by rank keeps trees shallow during union. Together they make each operation run in inverse-Ackermann time, which is at most about 4 in practice.

How do you detect a cycle in an undirected graph with Union Find?

Process edges one by one. If the two endpoints already have the same root, adding the edge creates a cycle.

14

Practice problems

ProblemDifficultyWhat it trains
547. Number of ProvincesMediumComponent counting.
684. Redundant ConnectionMediumCycle on union.
990. Satisfiability of Equality EquationsMediumUnion then check.
721. Accounts MergeMediumGrouping by shared keys.
1202. Smallest String With SwapsMediumSort within components.
1697. Checking Existence of Edge Length Limited PathsHardOffline sorted queries.