Pattern #56
Union Find / Disjoint Set Union
Important interview questions, thinking patterns, Path Compression, Union by Size, Undirected Cycle Detection, Kruskal's MST, and Go templates.
Must Solve
18 core questions — solve these first.
- 1.Number of Connected Components in an Undirected GraphInitialize DSU with n components; decrement on every successful Union(u, v)medium
- 2.Redundant ConnectionIterate edges; return the edge where Union(u, v) returns false (already connected)medium
- 3.Number of ProvincesUnion cities i and j if isConnected[i][j] == 1; return remaining DSU component countmedium
- 4.Graph Valid TreeVerify edges == n - 1 and all Union(u, v) succeed without cyclesmedium
- 5.Accounts MergeMap each email to an account index; Union accounts sharing emails; group emails by rootmedium
- 6.Most Stones Removed with Same Row or ColumnUnion stones sharing row or column; max removals = total stones - component countmedium
- 7.Number of Operations to Make Network ConnectedCheck if total edges >= n - 1; answer = remaining components - 1medium
- 8.Satisfiability of Equality EquationsUnion variables in "a==b"; verify for all "c!=d" that Find(c) != Find(d)medium
- 9.Smallest String With SwapsUnion indices in swap pairs; sort characters within each component rootmedium
- 10.Similar String GroupsUnion pairs of words that differ by <= 2 swap positions; return component counthard
- 11.Regions Cut By SlashesDivide each grid square into 4 triangles; Union adjacent triangles separated by slashesmedium
- 12.Largest Component Size by Common FactorUnion each number with its prime factors; return largest DSU component sizehard
- 13.Min Cost to Connect All PointsBuild Manhattan distance edges + Kruskal's MST using Union Findmedium
- 14.Kruskal's Minimum Spanning TreeSort edges by weight; add edge if Union(u, v) succeeds (endpoints in different components)medium
- 15.Number of Islands IIAdd land dynamically; Union neighboring 4-direction land cells; update island counthard
- 16.Remove Max Number of Edges to Keep Graph Fully TraversableDual DSU for Alice & Bob; prioritize Type 3 shared edges firsthard
- 17.Checking Existence of Edge Length Limited PathsOffline queries sorted by limit + Kruskal DSU edge additionshard
- 18.Find Critical and Pseudo-Critical Edges in MSTKruskal DSU MST forcing vs excluding individual edgeshard
Also Important
7 more questions worth practicing.
- 19.Sentence Similarity IIUnion similar word pairs; query Find(w1) == Find(w2)medium
- 20.Connecting Cities With Minimum CostStandard Kruskal's MST using Union Findmedium
- 21.Earliest Moment When Everyone Becomes FriendsSort timestamped friend logs; return time when DSU component count reaches 1medium
- 22.Minimize Malware SpreadFind component sizes of infected nodes; pick node whose removal maximizes clean component counthard
- 23.Couples Holding HandsUnion pairs of seats (2i, 2i+1); min swaps = N - DSU component counthard
- 24.Friend Requests with RestrictionsSimulate friend requests using DSU; check restriction rules before Unionhard
- 25.Dynamic Connectivity ProblemsAdvanced DSU with Rollback & segment tree query decompositionhard
How to Think
- Need repeatedly ask: are these connected?Union Find (DSU)
- Need merge groups?Union(u, v)
- Need representative of a group?Find(u)
- Adding edge creates cycle?Find(u) == Find(v) before edge addition
- Need Minimum Spanning Tree?Kruskal's Algorithm + DSU
Go DSU Struct Code Template
Complete DSU struct with Path Compression & Union by Size in Go
type DSU struct {
parent []int
size []int
}
func NewDSU(n int) *DSU {
p := make([]int, n)
s := make([]int, n)
for i := 0; i < n; i++ {
p[i] = i
s[i] = 1
}
return &DSU{parent: p, size: s}
}
// Find with Path Compression: O(alpha(N)) amortized (~O(1))
func (d *DSU) Find(x int) int {
if d.parent[x] != x {
d.parent[x] = d.Find(d.parent[x]) // Flatten tree!
}
return d.parent[x]
}
// Union by Size: O(alpha(N)) amortized (~O(1))
func (d *DSU) Union(a, b int) bool {
rootA := d.Find(a)
rootB := d.Find(b)
if rootA == rootB {
return false // Already connected! Same root -> Cycle detected!
}
// Attach smaller tree under larger tree
if d.size[rootA] < d.size[rootB] {
rootA, rootB = rootB, rootA
}
d.parent[rootB] = rootA
d.size[rootA] += d.size[rootB]
return true // Successful merge!
}👉 Total Time: Amortized O(α(N)) ≈ O(1) per op | Space: O(N) parent & size arrays
Path Compression & Union by Size
1. Path Compression: During Find(x), setting parent[x] = Find(parent[x]) re-links all visited nodes directly to the root, flattening tall tree chains to height 1!
2. Union by Size: When merging roots rootA and rootB, attach the smaller tree under the larger tree (d.parent[rootB] = rootA) to keep trees shallow.
3. Component Counter: Initialize components = n. Every time Union(u, v) returns true (successful merge), decrement components--.
Undirected Cycle Detection & Kruskal MST
1. Cycle Detection: If Find(u) == Find(v) before adding undirected edge u - v, nodes u and v are ALREADY connected! Adding edge u - v creates a cycle (used in Redundant Connection).
2. Kruskal's Minimum Spanning Tree: Sort all edges by weight $\to$ Iterate edges and call Union(u, v). If Union returns true, add edge weight to MST total; if false, skip (would create a cycle!).
DSU / Union Find → Efficiently track and merge connected components
Find(x) → parent[x] = Find(parent[x]) (Path Compression -> O(1))
Union(a, b) → Merge smaller root under larger root (Union by Size)
Find(u) == Find(v) -> Nodes already connected! Undirected Cycle Detected!
Kruskal MST → Sort edges by weight -> Add edge if Union(u, v) succeeds
Accounts Merge → Shared email identifier -> Union account IDs💡 Golden Rule: "Every connected group has one representative root; Find tells you the group, and Union merges two different groups into one."
Common Interview Mistakes
Wrong: parent[b] = a. Correct: rootA = Find(a); rootB = Find(b); parent[rootB] = rootA.
Wrong: parent[a] == parent[b]. Parents may differ while roots match! Correct: Find(a) == Find(b).
Only decrement components-- when Union(u, v) successfully merges two DIFFERENT roots!
Basic DSU is designed for UNDIRECTED connectivity! Use Kahn's Algorithm or 3-State DFS for DIRECTED cycle detection.
Interview Rules
- 1. Repeated connectivity queries? → Union Find / DSU
- 2. Find representative root? →
parent[x] = Find(parent[x])(Path Compression) - 3. Merge groups? → Attach smaller root under larger root (Union by Size)
- 4. Same root check? →
Find(u) == Find(v) - 5. Undirected cycle check? → If
Find(u) == Find(v)before adding edge $\implies$ Cycle! - 6. Redundant Connection? → Return edge where
Union(u, v) == false - 7. Minimum Spanning Tree? → Sort edges by weight + Kruskal DSU
- 8. Overall Complexity → Time:
O(α(N)) ≈ O(1)per operation | Space:O(N)
Small Rules
- Rule 1: Every connected component in DSU is identified by a single root node.
- Rule 2: Path compression flattens lookup paths so future queries take O(1) time.
- Rule 3: Union by size prevents deep tree structures when joining sets.
- Rule 4: Two nodes share an undirected cycle if their roots match before connecting them.
- Rule 5:Kruskal's MST processes edges in ascending weight order using DSU.
Production Thinking
Network Server Connectivity Queries → Instantly checking if two data center servers share a connected link
Identity Resolution Record Clustering → Merging duplicate user profiles sharing emails, phone numbers, or device IDs
Infrastructure Region Grouping → Grouping cloud compute nodes into connected availability zones
Image Connected Component Labeling → Merging adjacent image pixels into visual object clusters
Remember This
Union Find / DSU → Track & Merge Disjoint Groups
Find(x) → parent[x] = Find(parent[x]) (Path Compression)
Union(a, b) → Merge smaller root under larger root (Union by Size)
Same Root → Find(a) == Find(b) (Connected!)
Cycle Check → Find(u) == Find(v) before adding edge
Components → Start N, successful Union: --
Kruskal MST → Sort edges by weight + Union Find
Time → O(alpha(N)) per operation ≈ O(1)💡 Golden Rule: "Every connected group has one representative root; Find tells you the group, and Union merges two different groups into one."