Union Find
Initialization
1
2
3
4
5
6
7
1
2
3
4
5
6
7
union(2,4), union(5,7)
union(4,7)
1
2
3
4
5
6
7
find(7) = 2
What is Union Find
- A Data Structure that helps quickly union and find
- Compare with HashMap
- Hashmap is the best data structure to find
- Hashmap is slow at union O(n)
- Union find can be considered as trees (a forest)
An easy implementation
class UnionFind:
def __init__(self, n):
self.list = [i for i in range(n)]
def union(self, a, b):
ancestor_a = self.find(a)
ancestor_b = self.find(b)
if ancestor_a == ancestor_b:
return False
else:
self.list[ancestor_b] = ancestor_a
return True
def find(self, k):
i = k
while i != self.list[i]:
i = self.list[i] # Here i is the root.
return iWhat does it do?
- list is to keep each node's father
- initialization: each node is an independent tree with its own as the father
- find: keep finding above to get the root
- union: make one node root to point to another root
Question it can solve
- Graph connected components
- check connections or groups for Sets
Surrounded Region
Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'.
A region is captured by flipping all 'O's into 'X's in that surrounded region.
X X X X
X O O X
X X O X
X O X X
X X X X
X X X X
X X X X
X O X X
Surrounded Region
Before we use BFS or DFS to solve this question
But Union Find can also solve this question
Surrounded Region
class Solution:
def __init__(self):
self.list = []
self.edge = []
def solve(self, board: List[List[str]]) -> None:
if len(board) == 0 or len(board[0]) == 0:
return
m = len(board)
n = len(board[0])
for i in range(m * n):
x = i // n
y = i % n
if (x == 0 or x == m - 1 or y == 0 or y == n - 1) and (board[x][y] == 'O'):
self.edge.append(True)
else:
self.edge.append(False)
self.list.append(i)
for i in range(m * n):
x = i // n
y = i % n
if x < m - 1 and board[x][y] == board[x + 1][y]:
self.union(i, i + n)
if y < n - 1 and board[x][y] == board[x][y + 1]:
self.union(i, i + 1)
for i in range(m * n):
x = i // n
y = i % n
if board[x][y] == 'O' and not self.edge[self.find(i)]:
board[x][y] = 'X'Surrounded Region
def union(self, a, b):
ancestor_a = self.find(a)
ancestor_b = self.find(b)
if ancestor_a == ancestor_b:
return False
else:
self.list[ancestor_b] = ancestor_a
if self.edge[ancestor_b]:
self.edge[ancestor_a] = True
return True
def find(self, k):
i = k
while i != self.list[i]:
i = self.list[i] # Here i is the root.
return iFriend Circles
There are N students in a class. Some of them are friends, while some are not. Their friendship is transitive in nature. For example, if A is a directfriend of B, and B is a direct friend of C, then A is an indirect friend of C. And we defined a friend circle is a group of students who are direct or indirect friends.
Given a N*N matrix M representing the friend relationship between students in the class. If M[i][j] = 1, then the ith and jth students are directfriends with each other, otherwise not. And you have to output the total number of friend circles among all the students.
Friend Circles
Input:
[[1,1,0],
[1,1,0],
[0,0,1]]
Output: 2
Explanation:The 0th and 1st students are direct friends, so they are in a friend circle.
The 2nd student himself is in a friend circle. So return 2.
It is very intuitive that Union Find can solve the problem. We just need to keep doing the union and count after all how many sets there are.
Friend Circles
class Solution:
def __init__(self):
self.list = []
def union(self, a, b):
ancestor_a = self.find(a)
ancestor_b = self.find(b)
if ancestor_a == ancestor_b:
return
else:
self.list[ancestor_b] = ancestor_a
def find(self, k):
i = k
while i != self.list[i]:
i = self.list[i] # Here i is the root.
return i
def findCircleNum(self, M):
n = len(M)
count = n
for i in range(n):
self.list.append(i)
for i in range(n):
for j in range(i):
if M[i][j] == 1 and self.find(i) != self.find(j):
self.union(i, j)
count -= 1
return countYou are given an empty 2D binary grid grid of size m x n. The grid represents a map where 0's represent water and 1's represent land. Initially, all the cells of grid are water cells (i.e., all the cells are 0's).
We may perform an add land operation which turns the water at position into a land. You are given an array positions where positions[i] = [ri, ci] is the position (ri, ci) at which we should operate the ith operation.
Return an array of integers answer where answer[i] is the number of islands after turning the cell (ri, ci) into a land.
An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Input: m = 3, n = 3, positions = [[0,0],[0,1],[1,2],[2,1]]
Output: [1,1,2,3]
Explanation:
Initially, the 2d grid is filled with water.
- Operation #1: addLand(0, 0) turns the water at grid[0][0] into a land. We have 1 island.
- Operation #2: addLand(0, 1) turns the water at grid[0][1] into a land. We still have 1 island.
- Operation #3: addLand(1, 2) turns the water at grid[1][2] into a land. We have 2 islands.
- Operation #4: addLand(2, 1) turns the water at grid[2][1] into a land. We have 3 islands.
class Solution:
def numIslands2(self, m: int, n: int, positions: List[List[int]]) -> List[int]:
self.count = 0
self.seen = set()
self.father = [0] * (m * n)
def init(x, y):
index = x * n + y
if index not in self.seen:
self.father[index] = index
self.count += 1
self.seen.add(index)
def union(a, b):
fa = find(a)
fb = find(b)
if fa != fb:
self.father[fa] = fb
self.count -= 1
def find(x):
if x == self.father[x]:
return x
self.father[x] = find(self.father[x])
return self.father[x]
res = []
for x, y in positions:
init(x, y)
for d in ((1, 0), (0, 1), (-1, 0), (0, -1)):
nx = x + d[0]
ny = y + d[1]
# check up, down, left, right
if 0 <= nx < m and 0 <= ny < n and (nx * n + ny) in self.seen:
union(x * n + y, nx * n + ny)
res.append(self.count)
return res Potential improvement
- When you keep union, the tree could be very tall
- maintain a height so when union happens, the smaller tree union to the bigger tree. So it can help keep the tree height as small as possible
Copy of [GoValley-Jo] Union Find 11
By ZhiTongGuiGu
Copy of [GoValley-Jo] Union Find 11
- 70