Back LeetEye
Data Structure

Union-Find

Union-Find (also called Disjoint Set Union) tracks which elements belong to the same group. It's incredibly efficient for two operations: merging groups together (union) and checking if two elements are in the same group (find).

The Core Idea

Each group has a representative (root). To check if two elements are connected, check if they have the same root. To merge groups, make one root point to the other.

The Key Insight

With path compression and union by rank, both operations run in nearly O(1) time - technically O(α(n)), where α is the inverse Ackermann function. For all practical purposes, it's constant.

Classic Implementation

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n

    def find(self, x):
        if self.parent[x] != x:
            # Path compression
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        if px == py:
            return False  # Already connected

        # Union by rank
        if self.rank[px] < self.rank[py]:
            px, py = py, px
        self.parent[py] = px
        if self.rank[px] == self.rank[py]:
            self.rank[px] += 1
        return True

    def connected(self, x, y):
        return self.find(x) == self.find(y)

Classic: Number of Connected Components

def countComponents(n, edges):
    uf = UnionFind(n)
    components = n

    for a, b in edges:
        if uf.union(a, b):
            components -= 1  # Merged two groups

    return components

When to Use Union-Find

Pro Tip

Union-Find is often simpler than DFS/BFS for connectivity problems, especially when edges are added dynamically. If you're building up connections one at a time, think Union-Find.