并查集可以用来解决集合从属关系,很容易的可以获取如连通分量的个数,
其基本实现主要由三部分构成,即:
①find函数,用于寻找某一个节点的集合代表节点。
②union函数,用于将两个集合合并,简易并查集直接将二者合并,而优化后的并查集要求小集合并到大集合中。
③connected函数,用于判断两个节点是否从属于一个集合,在union中也会调用此函数
如例题:
class UnionFind:
father = {}
size = {}
cnt = 0
def __init__(self,M):
m = len(M)
for i in range(m):
self.father[i] = i # 初始时,每个节点指向自己
self.size[i] = 1 # 初始时,每个集合大小皆为1
self.cnt += 1 # 朋友圈数量
def find_father(self,node): # find函数,当前节点不等于其父节点时,将当前节点置为其父节点,最后返回的是代表节点
while node != self.father[node]:
node = self.father[node]
return node
def connected(self,A, B):
return self.find_father(A)==self.find_father(B)
def union(self,A, B):
if self.connected(A, B):
return
if self.size[self.find_father(A)] <= self.size[self.find_father(B)]:
self.father[self.find_father(A)] = self.find_father(B)
self.size[self.find_father(B)] += self.size[self.find_father(A)]
else:
self.father[self.find_father(B)] = self.find_father(A)
self.size[self.find_father(A)] += self.size[self.find_father(B)]
self.cnt -= 1
class Solution:
def findCircleNum(self, M: List[List[int]]) -> int:
n = len(M)
uf = UnionFind(M)
for i in range(n):
for j in range(i):
if M[i][j]==1:
uf.union(i,j)
return uf.cnt
注意,此题中size可以省略,对结果无影响,不过加入size字典可以有效的避免构建的类树集合节点失衡
此外,这里可以采用路径压缩算法改进
class UnionFind:
father = {}
size = {}
cnt = 0
def __init__(self,M):
m = len(M)
for i in range(m):
self.father[i] = i
self.size[i] = 1
self.cnt += 1
def find_father(self,node):
# 路径压缩
father_node = self.father[node]
if node != father_node:
father_node = self.find_father(father_node)
self.father[node] = father_node
return father_node
def connected(self,A, B):
return self.find_father(A)==self.find_father(B)
def union(self,A, B):
if self.connected(A, B):
return
if self.size[self.find_father(A)] <= self.size[self.find_father(B)]:
self.father[self.find_father(A)] = self.find_father(B)
self.size[self.find_father(B)] += self.size[self.find_father(A)]
else:
self.father[self.find_father(B)] = self.find_father(A)
self.size[self.find_father(A)] += self.size[self.find_father(B)]
self.cnt -= 1
class Solution:
def findCircleNum(self, M: List[List[int]]) -> int:
n = len(M)
uf = UnionFind(M)
for i in range(n):
for j in range(i):
if M[i][j]==1:
uf.union(i,j)
return uf.cnt