Quick Overview
Union-Find flattens each chain as it walks it, so repeated lookups get cheaper rather than slower. With path compression and union by rank, `find` settles at a near-constant `O(alpha(N))`.
The Disjoint Set Union (DSU) data structure (also called Union-Find) maintains a collection of disjoint (non-overlapping) sets. It supports two primary operations:
find(x): Determine which set element x belongs to (returns representative root).union(x, y): Merge the set containing x with the set containing y.Without optimizations, tree depths can degenerate to O(N). Two optimizations make DSU run in near O(1) amortized time (O(α(N)) Inverse Ackermann function):
find() so every visited node points directly to the root.class DisjointSet {
constructor(size) {
this.parent = Array.from({ length: size }, (_, i) => i);
this.rank = new Array(size).fill(0);
this.numComponents = size;
}
find(x) {
// Path compression: Point node directly to root!
if (this.parent[x] !== x) {
this.parent[x] = this.find(this.parent[x]);
}
return this.parent[x];
}
union(x, y) {
const rootX = this.find(x);
const rootY = this.find(y);
if (rootX === rootY) return false; // Already in the same set!
// Union by rank
if (this.rank[rootX] < this.rank[rootY]) {
this.parent[rootX] = rootY;
} else if (this.rank[rootX] > this.rank[rootY]) {
this.parent[rootY] = rootX;
} else {
this.parent[rootY] = rootX;
this.rank[rootX]++;
}
this.numComponents--;
return true;
}
}
const dsu = new DisjointSet(5);
dsu.union(0, 1);
dsu.union(1, 2);
console.log(dsu.find(0) === dsu.find(2)); // Output: true (0 and 2 are connected!)
console.log(dsu.find(0) === dsu.find(3)); // Output: false
find() degrades performance to O(N) on deep linear chains.Use DSU for instant network connectivity queries. Next, let's explore Dynamic Programming: Memoization vs. Tabulation!
Big O describes how work grows, not how long it takes. An `O(N^2)` algorithm on 1,000 items does a million steps; the same work at `O(N log N)` does about 10,000.
A dynamic array doubles rather than growing by one, so the expensive copy lands on the 1st, 2nd, 4th and 8th push. Averaged across every push, that is `O(1)` amortised.
A nested loop tests every pair in `O(N^2)`. On sorted data, moving two pointers inward from both ends rules out half the remaining candidates at each step and settles it in one `O(N)` pass.
Average 5.0 by 1 learner