Recognize the Pattern
- Edges or shared identifiers repeatedly merge groups.
- You need connectivity or component counts after each merge.
- Connections are added, not arbitrarily removed.
Core Invariant
Every component has one representative. Only merging different representatives reduces the component count.
Important Boundary
Parent pointers describe the DSU forest, not routes in the original graph. This template supports merges, not connection deletion.
One representative per component
Each root points to itself. Following parent pointers reaches the representative of a component. Two nodes are connected exactly when their representatives match.
Only root sizes are authoritative. Union by size attaches the smaller component's root to the larger one's root. Path compression makes the nodes visited by find point directly to their representative. Neither optimization changes which elements are connected.
- Compare representatives, not immediate parents.
- Decrease the component count only when two different roots merge.
- The chosen root can change. Do not give its numeric ID domain meaning.
Keep this standalone template handy
Use dense indices 0 through n-1. Map string identifiers to indices before constructing the DSU when necessary. The public method names match the Accounts Merge solution. The reusable class stores only parents and sizes.
Template Assumptions
- Fixed IDs 0 through n - 1; map emails or other identifiers to IDs first.
- unionBySize returns true only when different roots merge. Keep an optional group counter outside the class and decrease it only on true.
JavaScript Template
- unionBySize returns false for an already-connected pair. Duplicate connections do not change sizes or counts.
- If a problem needs the number of groups, keep let components = n outside the class. For each connection, use if (dsu.unionBySize(u, v)) components--. Problems that only group elements do not need this counter.
- Use findUnionParent again when grouping results: an earlier representative may have been attached to another root.
- Union by size bounds parent-chain depth by O(log N) even before compression. This recursion is not the same risk as walking an arbitrary 100000-node input chain.
Trace merges without confusing roots and edges
This walkthrough also tracks an optional component count outside the DSU. Start it at n and decrease it only when unionBySize returns true.
In Accounts Merge, a shared email supplies evidence that two account indices belong to one component. The same name alone is not evidence. Deduplicate emails before producing sorted output.
For timestamped friendship events, sort by time, union each pair, and stop when the component count reaches one. The sorting cost is separate from DSU operations.
| Operation | parent[] | size[] (only roots authoritative) | Components |
|---|---|---|---|
| Initialize | [0,1,2,3] | [1,1,1,1] | 4 |
| unionBySize(0,1) | [0,0,2,3] | [2,1,1,1] | 3 |
| unionBySize(2,3) | [0,0,2,2] | [2,1,2,1] | 2 |
| unionBySize(1,2) | [0,0,0,2] | [4,1,2,1] | 1 |
| findUnionParent(3) | [0,0,0,0] | [4,1,2,1] | 1 |
| unionBySize(0,3) | [0,0,0,0] | [4,1,2,1] | 1 |
- Begin with four roots: components = 4 and sizes are all 1.
- unionBySize(0,1) creates {0,1}; components = 3.
- unionBySize(2,3) creates {2,3}; components = 2.
- unionBySize(1,2) joins the two representatives; components = 1.
- unionBySize(0,3) returns false because they already share a representative.
Step-by-Step: Union find: roots, sizes, and path compression
- parent[]
- [0,1,2,3]
- size[] (only roots count)
- [1,1,1,1]
- Components
- 4
Start with four roots
Each node is its own parent. There are four components, each of size one. The lines in this diagram are parent links, not original graph edges.
When a traversal is the better tool
Path With Maximum Minimum Value can activate cells in descending value order and union adjacent active cells. The first value at which start and end become connected is the threshold. That approach must also pay for sorting; a priority queue offers a different implementation.
| Need | Prefer | Reason |
|---|---|---|
| One component count on a static graph | BFS or DFS | Linear traversal is simple and also exposes vertices. |
| Connectivity after many added edges | DSU | Avoid traversing the graph after every addition. |
| An actual route or shortest path | Graph search | DSU does not retain route information. |
| Directed reachability or strongly connected components | Directed graph algorithms | Merging endpoints ignores edge direction. |
| Arbitrary deletions | A different connectivity strategy | Ordinary DSU has no split operation. |
Separate DSU cost from the rest of the problem
- Initialization uses O(N) time and space.
- Union by size with path compression gives O(alpha(N)) amortized time per find or union across a sequence of operations. alpha is the inverse Ackermann function; this is not a worst-case O(1) guarantee for every call.
- Sorting E events costs O(E log E); grouping and sorting account emails adds its own cost.
- Update size at the receiving root with +=. Assigning the smaller size instead corrupts the weighting heuristic.
Mistakes and Counterexamples
Compare immediate parents rather than representatives.
Counterexample: With parent = [0,0,0,2], nodes 1 and 3 have different immediate parents but both belong to root 0.
Correction: Compare findUnionParent(1) with findUnionParent(3). Compression is an optimization, not a prerequisite for connectivity.
Decrease the component count for every input edge.
Counterexample: After union(0,1), another union(1,0) does not connect new groups. Counting both merges reports too few components.
Correction: Change sizes and the component count only when the roots differ.
Merge accounts because their names match.
Counterexample: [Alex, a@example.com] and [Alex, b@example.com] have no shared identifier; the repeated name is not proof they belong together.
Correction: Use shared emails as evidence of connectivity. Names label the merged result rather than determining unions.
Last-Minute Recap
- Union representatives, not arbitrary nodes.
- Repeated unions are no-ops.
- Connectivity, sorting, and output construction have separate costs.
Explain It in an Interview
- What does find return, and why is checking immediate parents insufficient?
- Why combine union by size with path compression?
- What would you use instead if the task asks for an actual route?
Ready to Apply This Pattern?
Before coding, explain why this pattern fits and what must stay true at each step. Start with an easier problem, then test that reasoning on a harder variation.
Ordered from Easy to Hard. Premium access requirements still apply.
- 1.The Earliest Moment When Everyone Become FriendsSeparate sorting events from detecting the first single-component state.Medium
- 2.Accounts MergeTurn shared emails into unions; group unique emails using final representatives.Medium
- 3.Number of ProvincesUnion connected cities and count distinct representatives without double-counting repeated edges.Medium
- 4.Path With Maximum Minimum ValueActivate cells by threshold and connect only already-active neighbors.Hard