Code Templates
Union Find
Use Cases for Union Find
| Use Case | Description | Example |
|---|---|---|
| Connected Components | Determine if two nodes are in the same connected component in a graph. | In a social network, check if two users are in the same group. |
| Network Connectivity | Monitor the connectivity of a network as connections are added or removed. | In a computer network, determine if two devices can communicate after a new connection is made. |
| Kruskal's Minimum Spanning Tree | Use Union-Find to detect cycles while constructing a minimum spanning tree. | In a graph of cities, find the minimum cost to connect all cities without any cycles. |
Code Template
Initializing variables
self.parent = [i for i in range(size)]:Creates aparentarray where each element points to itself, indicating that each element is its own set initially.self.rank = [1] * size:Initializes arankarray, where each element starts with a rank of 1, used to optimize union operations by keeping track of tree depth.
Find function
- This method is designed to find the root or representative of the set containing element
p. if self.parent[p] != p:This line checks if the element p is its own parent. If not, it meanspis not the root of its set.self.parent[p] = self.find(self.parent[p]):Ifpis not the root, this line recursively calls find on p's parent. The result is then assigned back toself.parent[p], effectively flattening the structure (path compression). This means that all nodes in the path from p to its root will now point directly to the root, speeding up future queries.
Union function
rootP = self.find(p)androotQ = self.find(q):Usefindto get the representative roots forpandq.- If both roots are already the same,
unionreturnsFalsebecause no merge happened. - Otherwise, the root with the higher
rankbecomes the parent. If ranks are equal, one root becomes the parent and itsrankis incremented. ReturnTrueto signal that two components were merged.
Check connection
connected(p, q)compares the roots ofpandq. If the roots are the same, both nodes are in the same connected component.
class UnionFind:def __init__(self, size):self.parent = [i for i in range(size)]self.rank = [1] * size
Common mistakes
- Wrong Path Compression Implementation
# Wrong: no path compressiondef find(self, p):while self.parent[p] != p: # Just traverses upp = self.parent[p]return p# Wrong: incorrect recursiondef find(self, p):if self.parent[p] != p:return self.find(self.parent[p]) # Doesn't compress# Correct:def find(self, p):if self.parent[p] != p:self.parent[p] = self.find(self.parent[p])return self.parent[p]
- Wrong Union by Rank Implementation
# Wrong: not using ranksdef union(self, p, q):rootP = self.find(p)rootQ = self.find(q)self.parent[rootQ] = rootP # Always merges to rootP# Wrong: incorrect rank updatedef union(self, p, q):if self.rank[rootP] == self.rank[rootQ]:self.rank[rootP] += 1self.rank[rootQ] += 1 # Should only increment one# Correct:if self.rank[rootP] == self.rank[rootQ]:self.parent[rootQ] = rootPself.rank[rootP] += 1
- Wrong Connected Check
# Wrong: not using finddef connected(self, p, q):return self.parent[p] == self.parent[q] # Should use find()# Wrong: redundant findsdef connected(self, p, q):rootP = self.find(p)rootQ = self.find(q)return self.find(rootP) == self.find(rootQ) # Unnecessary finds# Correct:def connected(self, p, q):return self.find(p) == self.find(q)
Issues and consideration
- Thread Safety: If the class is intended for concurrent use, consider implementing locking mechanisms to prevent race conditions.
Related Problem
class UnionFind:def __init__(self, size):self.parent = [i for i in range(size)]self.rank = [1] * sizedef find(self, p):if self.parent[p] != p:self.parent[p] = self.find(self.parent[p])return self.parent[p]def union(self, p, q):rootP = self.find(p)rootQ = self.find(q)if rootP == rootQ:return Falseif self.rank[rootP] > self.rank[rootQ]:self.parent[rootQ] = rootPelif self.rank[rootP] < self.rank[rootQ]:self.parent[rootP] = rootQelse:self.parent[rootQ] = rootPself.rank[rootP] += 1return Truedef connected(self, p, q):return self.find(p) == self.find(q)class Solution:def numIslands(self, grid: List[List[str]]) -> int:if not grid:return 0rows = len(grid)cols = len(grid[0])uf = UnionFind(rows * cols)count = 0for i in range(rows):for j in range(cols):if grid[i][j] == "1":count += 1for di, dj in [(0, 1), (1, 0)]:ni, nj = i + di, j + djif (0 <= ni < rows and0 <= nj < cols andgrid[ni][nj] == "1"):if uf.union(i * cols + j, ni * cols + nj):count -= 1return count
class UnionFind:def __init__(self, size):self.parent = [i for i in range(size)]self.rank = [1] * sizedef find(self, p):if self.parent[p] != p:self.parent[p] = self.find(self.parent[p])return self.parent[p]def union(self, p, q):rootP = self.find(p)rootQ = self.find(q)if rootP == rootQ:return Falseif self.rank[rootP] > self.rank[rootQ]:self.parent[rootQ] = rootPelif self.rank[rootP] < self.rank[rootQ]:self.parent[rootP] = rootQelse:self.parent[rootQ] = rootPself.rank[rootP] += 1return Truedef connected(self, p, q):return self.find(p) == self.find(q)class Solution:def findCircleNum(self, isConnected: List[List[int]]) -> int:if not isConnected:return 0n = len(isConnected)uf = UnionFind(n)provinces = nfor i in range(n):for j in range(i + 1, n):if isConnected[i][j] == 1 and uf.union(i, j):provinces -= 1return provinces