Connectivity, cycle detection, and clustering in undirected networks
89 problems·1 Easy·50 Medium·38 Hard
Pattern Study Guide & Cheat Sheet· O(α(N)) ≈ O(1) amortized per operation · O(N) for parent and rank arrays
▼
Disjoint Set Union (DSU) tracks partitions and connectivity of elements, merging groups and querying whether two elements share a component in near-constant O(α(N)) time.
Core Invariant: Maintain representative parent pointers. With Path Compression (`parent[x] = find(parent[x])`) and Union by Rank, tree depth remains <= 4 for all practical universe scales (inverse Ackermann α(N)).
Recognize it (Keywords & Signals)
Connected components in an undirected network
Redundant connection / cycle detection in undirected graph
Number of provinces / islands / friend circles
Graph valid tree (exactly n - 1 edges and 1 connected component)
Minimum Spanning Tree (Kruskal's algorithm)
When NOT to use
Directed graphs (DSU cannot handle edge directions; use Topological Sort or Tarjan / Kosaraju).
How to solve (Step-by-step)
1.Initialize `parent = list(range(n))` and `rank = [1] * n`.
2.Implement `find(x)`: recursively find root while flattening tree (`parent[x] = find(parent[x])`).
3.Implement `union(x, y)`: find roots `rx = find(x)`, `ry = find(y)`. If equal, they already connect (cycle detected!).
4.If unequal, attach smaller rank root under larger rank root, and decrement component count.
5.Return True if merged, False if already connected.
Watch for (Interview Traps)
Comparing raw node IDs instead of representative roots (`x == y` instead of `find(x) == find(y)`)
Omitting path compression: operations degenerate to O(N) linear chains without it
Using DSU on directed graphs where edge orientation matters
Disjoint Set Union (DSU) with Path Compression & Rank
class UnionFind:
def __init__(self, size: int):
self.parent = list(range(size))
self.rank = [1] * size
self.components = size
def find(self, x: int) -> int:
if self.parent[x] != x:
# Path compression: flatten path directly to root
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, x: int, y: int) -> bool:
root_x, root_y = self.find(x), self.find(y)
if root_x == root_y:
return False # Already in same set (cycle detected!)
# Union by rank: attach smaller tree under larger tree
if self.rank[root_x] > self.rank[root_y]:
self.parent[root_y] = root_x
elif self.rank[root_x] < self.rank[root_y]:
self.parent[root_x] = root_y
else:
self.parent[root_y] = root_x
self.rank[root_x] += 1
self.components -= 1
return True
Cost
O(α(N)) ≈ O(1) amortized per operation · O(N) for parent and rank arrays (Inverse Ackermann α(N) never exceeds 4 for any practical input size.)
Canonical problems
#547 Number of Provinces:Union cities with direct flights; return final component count
#684 Redundant Connection:First edge where union returns False creates the cycle
#261 Graph Valid Tree:Must have exactly n - 1 edges and 1 connected component
#128 Longest Consecutive Sequence:Union adjacent numbers x and x+1
What is the Union-Find (Disjoint Set) pattern in coding interviews?
Connectivity, cycle detection, and clustering in undirected networks It is categorized under Data Structures and features 89 curated interview problems across Easy (1), Medium (50), and Hard (38) difficulties.
Which tech companies frequently test Union-Find (Disjoint Set)?
How do I master the Union-Find (Disjoint Set) pattern?
Start by studying the algorithmic strategy and template code, then practice Easy and Medium problems before attempting Hard problems under timed conditions.