Leetcode 261. 以图判树
1.题目基本信息
1.1.题目描述
给定编号从 0 到 n - 1 的 n 个结点。给定一个整数 n 和一个 edges 列表,其中 edges[i] = [ai, bi] 表示图中节点 ai 和 bi 之间存在一条无向边。
如果这些边能够形成一个合法有效的树结构,则返回 true ,否则返回 false 。
1.2.题目地址
https://leetcode.cn/problems/graph-valid-tree/description/
2.解题方法
2.1.解题思路
并查集
2.2.解题步骤
并查集方法步骤
-
第一步,构建并查集,并将所有的节点添加到并查集中
-
第二步,遍历所有的边,将相关相连的点进行连接,如果边的两端都在同一个集合中,则代表存在环,直接返回false
-
第三步,如果图中无环,则只要并查集中的集合数为1就能保证图能构建成熟
DFS方法步骤
-
第一步,构建邻接表和访问状态(分为未访问、访问中、已访问)
-
第二步,构建递归函数。递归任务:返回node所在连通分量中是否有环
-
第三步,如果图中无环且只有一个连通分量则可以构建成树
3.解题代码
DFS版本代码
class Solution:
# 判断无向图有无环:DFS+三色标记法
def validTree(self, n: int, edges: List[List[int]]) -> bool:
# 第一步,构建邻接表和访问状态(分为未访问、访问中、已访问)
graph=[[] for _ in range(n)]
for edge in edges:
graph[edge[0]].append(edge[1])
graph[edge[1]].append(edge[0])
states=[0]*n # 0表示未访问,1表示访问中,2表示已访问
# 第二步,构建递归函数。递归任务:返回node所在连通分量中是否有环
def dfs(node,parentNode):
for subNode in graph[node]:
if subNode==parentNode:
continue
if states[subNode]==1:
return True
elif states[subNode]==0:
states[subNode]=1
if dfs(subNode,node):
return True
states[node]=2
return False
# 第三步,如果图中无环且只有一个连通分量则可以构建成树
states[0]=1
return not dfs(0,-1) and all([states[i]==2 for i in range(n)])
并查集版本代码
# # ==> 并查集模板(附优化)
class UnionFind():
def __init__(self):
self.roots={}
self.setCnt=0 # 连通分量的个数
# Union优化:存储根节点主导的集合的总节点数
self.rootSizes={}
def add(self,x):
if x not in self.roots:
self.roots[x]=x
self.rootSizes[x]=1
self.setCnt+=1
def find(self,x):
root=x
while root != self.roots[root]:
root=self.roots[root]
# 优化:压缩路径
while x!=root:
temp=self.roots[x]
self.roots[x]=root
x=temp
return root
def union(self,x,y):
rootx,rooty=self.find(x),self.find(y)
if rootx!=rooty:
# 优化:小树合并到大树上
if self.rootSizes[rootx]<self.rootSizes[rooty]:
self.roots[rootx]=rooty
self.rootSizes[rooty]+=self.rootSizes[rootx]
else:
self.roots[rooty]=rootx
self.rootSizes[rootx]+=self.rootSizes[rooty]
self.setCnt-=1
class Solution:
# 并查集
def validTree(self, n: int, edges: List[List[int]]) -> bool:
# 第一步,构建并查集,并将所有的节点添加到并查集中
uf=UnionFind()
for i in range(n):
uf.add(i)
# 第二步,遍历所有的边,将相关相连的点进行连接,如果边的两端都在同一个集合中,则代表存在环,直接返回false
for node1,node2 in edges:
if uf.find(node1)!=uf.find(node2):
uf.union(node1,node2)
else:
# 有环
return False
# 第三步,如果图中无环,则只要并查集中的集合数为1就能保证图能构建成熟
return uf.setCnt==1