第一次参加蓝桥杯,也是最后一次了。我是个小白,准备几个模板到时候坐牢也不会那么难受吧。
1、并查集的用途
- 查询元素a和元素b是否属于同一组
- 合并元素a和元素b所在的组
2、并查集的结构
- 每个元素对应一个节点,每个组对应一棵树。
- 在并査集中,哪个节点是哪个节点的父亲以及树的形状等信息无需多加关注,整体组成一个树形结构才是重要的。
(1) 初始化
准备n节点来表示n个元素。最开始时没有边。
(2) 合并
从一个组的根向另一个组的根连边,这样两棵树就变成了一棵树,也就把两个组合并为一个组了。
(3) 查询
为了査询两个节点是否属于同一组,我们需要沿着树向上走 ,来査询包含这个元素的树的根是谁。.
如果两个节点走到了同一个根,那么就可以知道它们属于同一组。
3、并查集实现中的注意点
- 对于每棵树,记录这棵树的高度(rank)。
- 合并时如果两棵树的rank不同,那么从rank小的向rank大的连边。
- 此外,通过路径压缩,可以使得并査集更加高效。对于每个节点,一旦向上走到了一次根节点,就把这个点到父亲的边改为直接连向根。在此之上,不仅仅是所查询的节点,在查询过程中向上经过的所有的节点,都改为直接连到根上。这样再次查询这些节点时,就可以很快知道根是谁了。
4、并查集的复杂度
O ( α ( n ) ) O(\alpha(n)) O(α(n))
5、并查集的实现
class unionFindSet(object):
def __init__(self, n):
self.parent = list(range(n))
self.rank = [0] * n
def find(self, x):
if self.parent[x] == x:
return x
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def unite(self, x, y):
x, y = self.find(x), self.find(y)
if x == y:
return
if self.rank[x] < self.rank[y]:
self.parent[x] = y
else:
self.parent[y] = x
if self.rank[x] == self.rank[y]:
self.rank[x] += 1
def same(self, x, y):
return self.find(x) == self.find(y)
LeetCode并查集题
# 把上面那段复制下来
class Solution(object):
def minCostConnectPoints(self, points):
distince = lambda x, y : abs(points[x][0] - points[y][0]) + abs(points[x][1] - points[y][1])
edges = []
n = len(points)
for i in range(n - 1):
for j in range(i + 1, n):
edges.append((i, j, distince(i, j)))
edges.sort(key = lambda x : x[2])
num = 1
ans = 0
ufs = unionFindSet(n)
for x, y, length in edges:
if not ufs.same(x, y):
num += 1
ans += length
ufs.unite(x, y)
if num == n:
break
return ans