Lesson 17 / 26
Connected Components and Union-Find
Count and merge groups.
DFS flood fill or a disjoint-set union
Counting islands or friend circles means counting connected components: start a DFS or BFS from each unvisited node and mark everything reachable. Union-find (disjoint set union) keeps a parent pointer per node, merges sets with union and finds representatives with find; with path compression it is nearly O(1) per operation. It shines when edges arrive one at a time and detects cycles in undirected graphs (a union of already-connected nodes).
Islands with DFS and cycle detection with union-find, run
I ran this with Python 3.12.3 (standard library only). The grid has 3 islands; the fourth edge (2, 0) connects nodes already in one set, revealing a cycle; 5 nodes form 2 components.
# Counting islands with DFS, and the same idea with union-find
def count_islands(grid):
grid = [list(row) for row in grid]
rows, cols, count = len(grid), len(grid[0]), 0
def sink(r, c):
stack = [(r, c)]
while stack:
r, c = stack.pop()
if 0 <= r < rows and 0 <= c < cols and grid[r][c] == "1":
grid[r][c] = "0"
stack.extend([(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)])
for r in range(rows):
for c in range(cols):
if grid[r][c] == "1":
count += 1
sink(r, c)
return count
class DSU:
def __init__(self, n):
self.parent = list(range(n))
def find(self, x):
while self.parent[x] != x:
self.parent[x] = self.parent[self.parent[x]] # path halving
x = self.parent[x]
return x
def union(self, a, b):
ra, rb = self.find(a), self.find(b)
if ra == rb:
return False
self.parent[ra] = rb
return True
print(count_islands(["11000", "11000", "00100", "00011"]))
d = DSU(5)
edges = [(0, 1), (1, 2), (3, 4), (2, 0)]
print([d.union(a, b) for a, b in edges]) # False: edge (2,0) closes a cycle
print("components:", len({d.find(i) for i in range(5)}))
Output:
3 [True, True, True, False] components: 2
Use an explicit stack for big grids
Recursive DFS can hit Python's recursion limit on large grids; an explicit stack avoids it.
Quick check: What does a failed union (both nodes already share a root) indicate in an undirected graph?
- The nodes are disconnected
- The graph is empty
- The edge would create a cycle
- The algorithm has a bug
Answer
The edge would create a cycle — They were already connected.