返回
LeetCode 題目下如何巧妙應用 Union-Find 算法?
见解分享
2023-12-18 15:11:51
Union-Find 算法:图论中的连通性神器
Union-Find 算法概述
在图论中,Union-Find 算法是一种强大的工具,用于动态维护图中元素的连通性信息。它包含两个基本操作:
- union(a, b) :合并两个元素
a
和b
所在的集合。 - find(a) :返回元素
a
所在集合的代表元素。
应用场景
Union-Find 算法在解决以下问题时特别有用:
- 检测两个元素是否属于同一集合。
- 寻找某个集合的所有元素。
- 计算图中连通分量的数量。
- 构造最小生成树。
LeetCode 题目中的应用
岛屿数量
给定一个由 0
(水)和 1
(陆地)组成的网格,计算网格中岛屿的数量。
我们可以使用 Union-Find 算法轻松解决这个问题。首先,将每个陆地元素视为一个单独的集合。然后,检查每个陆地元素的上下左右相邻元素,如果相邻元素也为陆地,则将它们合并到同一个集合中。最后,统计集合的数量,即可得到岛屿的数量。
朋友圈
给定一个 n x n
的矩阵,其中 M[i][j]
表示人 i
和人 j
是否是朋友。计算朋友圈的数量。
同样,我们可以使用 Union-Find 算法解决这个问题。首先,将每个人视为一个单独的集合。然后,检查每个 M[i][j]
为 1
的情况,如果人 i
和人 j
是朋友,则将他们合并到同一个集合中。最后,统计集合的数量,即可得到朋友圈的数量。
代码示例
岛屿数量
def num_islands(grid):
"""
:type grid: List[List[str]]
:rtype: int
"""
if not grid:
return 0
m, n = len(grid), len(grid[0])
uf = UnionFind(m * n)
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
# 将当前陆地与上下左右相邻陆地合并
if i > 0 and grid[i - 1][j] == '1':
uf.union(i * n + j, (i - 1) * n + j)
if j > 0 and grid[i][j - 1] == '1':
uf.union(i * n + j, i * n + j - 1)
if i < m - 1 and grid[i + 1][j] == '1':
uf.union(i * n + j, (i + 1) * n + j)
if j < n - 1 and grid[i][j + 1] == '1':
uf.union(i * n + j, i * n + j + 1)
return uf.count
class UnionFind:
def __init__(self, n):
self.parent = [i for i in range(n)]
self.count = n
def find(self, x):
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, p, q):
root_p = self.find(p)
root_q = self.find(q)
if root_p != root_q:
self.parent[root_p] = root_q
self.count -= 1
朋友圈
def find_circle_num(M):
"""
:type M: List[List[int]]
:rtype: int
"""
if not M:
return 0
n = len(M)
uf = UnionFind(n)
for i in range(n):
for j in range(i + 1, n):
if M[i][j] == 1:
uf.union(i, j)
return uf.count
class UnionFind:
def __init__(self, n):
self.parent = [i for i in range(n)]
self.count = n
def find(self, x):
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, p, q):
root_p = self.find(p)
root_q = self.find(q)
if root_p != root_q:
self.parent[root_p] = root_q
self.count -= 1
常见问题解答
-
Union-Find 算法的复杂度是多少?
- find 和 union 操作的平均复杂度为 O(α(n)),其中 α(n) 是反阿克曼函数,增长极其缓慢。
-
Union-Find 算法适用于稀疏图吗?
- 适用于稀疏图,因为稀疏图中并不会频繁发生合并操作,可以将平均复杂度降至 O(1)。
-
Union-Find 算法是如何优化存储空间的?
- 通过路径压缩技术,将每个元素的父元素直接指向集合的根节点,从而优化存储空间。
-
Union-Find 算法有哪些变种?
- 加权并查集:根据元素的权重优化合并操作,以降低复杂度。
- 路径分裂并查集:通过路径分裂技术进一步降低路径压缩后的树的高度。
-
在实际应用中,Union-Find 算法有什么优势?
- 能够快速高效地处理动态连通性问题,例如社交网络中的好友分组、网络流量分析中的连通分量检测等。