684 冗余连接
1.题目描述
leetcode 684 就是多加一条边就形成闭环了,删掉最后一条边就不是闭环了,
2.代码如下:
class Solution:
def findRedundantConnection(self, edges: List[List[int]]) -> List[int]:
# 节点的个数
nodesCount = len(edges)
# 边的个数,定义一个节点list
# list(5),产生一个0-4的list
parent = list(range(nodesCount + 1))
# 查找节点的父节点,!!!并且将所有一个联通结合的父节点都设置为了最后一个点
def find(index: int) -> int:
# 递归查找父节点,直到他是自己的
if parent[index] != index:
parent[index] = find(parent[index])
return parent[index]
# 合并两个连通分量,使得index1节点的父节点设置为index2的父节点
def union(index1: int, index2: int):
parent[find(index1)] = find(index2)
for node1, node2 in edges:
# 如果两个节点的父节点不同,即连通分量不同,则合并
if find(node1) != find(node2):
union(node1, node2)
else:
# 如果两个节点的父节点,即连通分量相同,则返回
return [node1, node2]
return []
3.解释
该题就是通过判断新加入的一条边的两个端点是否已经连通,连通在并查集中就是判断两个点是否在一个连通分量中,那么就得将已有的节点合并成连通分量,若新加入的点若是连通则加入集合中(即将该点的父节点设置为已经在连通分量那一点的父节点)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xFE8QHuG-1610610450493)(C:\Users\70902\AppData\Roaming\Typora\typora-user-images\image-20210114144609666.png)]
4.并查集相关
并查集逻辑上是森林,我们可以选出一个根节点作为代表,其他子结点指向根结点表示都在同一片森林中。在这里,并不关心结点的子结点是谁,只关心父结点是谁,所以物理上可以简单用python的列表来表示并查集,列表的下标表示结点,列表元素的值表示父结点。
并查集一般包括初始化,查找根节点,合并,判断是否在一个树中。
class UnionFind(object):
# 并查集初始化
# 初始化的作用就是在list中用一种特殊的方式表示初始元素每一个都在一个单独的集合,即父节点都不一样,即list中的元素都不一样
def __init__(self, n):
# 并查集每个单独的元素自成一个元素
# 0 - n
self.uf = [i for i in range(n + 1)]
# 或者用-1表示集合的根节点
self.uf = [-1 for i in range(n + 1)]
self.sets_count = n
def find(self, p):
while self.uf[p] >= 0:
p = self.uf[p]
return p
# 查找的过程中可以路径压缩,减小下一次查找的复杂度
#路径压缩:在子节点的查找过程中,将子节点的父节点统统改为根节点
def find(self, p):
#尾递归
if self.uf[p] < 0:
return p
self.uf[p] = self.find(self.uf[p])
return self.uf[p]
def find(self, p):
#"""查找p的根结点(祖先)"""
r = p # 初始p
while self.uf[p] > 0:
p = self.uf[p]
while r != p: # 路径压缩, 把搜索下来的结点祖先全指向根结点
self.uf[r], r = p, self.uf[r]
# 相当于
self.uf[r] = p
r = self.uf[r]
return p
# 有向图连通
def union(self, p, q):
#"""连通p,q 让q指向p"""
proot = self.find(p)
qroot = self.find(q)
if proot == qroot:
return
elif self.uf[proot] > self.uf[qroot]: # 负数比较, 左边规模更小
self.uf[qroot] += self.uf[proot]
self.uf[proot] = qroot
else:
# 其实这里有点不太明白为什么规模相加是这么加的……每一个集合的uf[proot]根节点的父节点存在是这个集合的总数?
self.uf[proot] += self.uf[qroot] # 规模相加
self.uf[qroot] = proot
self.sets_count -= 1 # 连通后集合总数减一
def is_connected(self, p, q):
return self.find(p) == self.find(q)
5.刷题Tips
def is_connected(self, p, q):
return self.find(p) == self.find(q)
## 5.刷题Tips
无向图连通性 考虑 并查集 有向图依赖性 考虑 深度广度优先 拓扑排序