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

4.执行结果

Leetcode 261. 以图判树_第1张图片

你可能感兴趣的:(leetcode,算法,DFS,并查集)