leetcode323.无向图中连通分量的数目「并查集」

1.题目描述

给定编号从 0 到 n-1 的 n 个节点和一个无向边列表(每条边都是一对节点),请编写一个函数来计算无向图中连通分量的数目。

示例 1:

输入: n = 5 和 edges = [[0, 1], [1, 2], [3, 4]]

     0           3
     |             |
     1 --- 2    4 

输出: 2
示例 2:

输入: n = 5 和 edges = [[0, 1], [1, 2], [2, 3], [3, 4]]

     0             4
     |               |
     1 --- 2 --- 3

输出:  1

2.解题思路

1.dfs

参考:https://blog.csdn.net/qq_19782019/article/details/82590527

2.迭代+栈

初始时,起始顶点V0入栈,其对应的visited[V0]设置为True,迭代过程如下:

  • 1.检测堆栈是否为空,若堆栈为空,迭代结束
  • 2.从栈中弹出一个顶点v,访问v
  • 3.将v的未被访问的邻接顶点压入栈中,并将这些顶点的visited置为True
  • 4.执行步骤1

3.bfs

参考:https://blog.csdn.net/qq_19782019/article/details/82659964

4.并查集

3.代码实现

1.dfs

class Solution:
    def dfs(self,i,graph,visited):
        for t in graph[i]:
            if t not in visited:
                visited.add(t)
                self.dfs(t,graph,visited)                

    def countComponents(self, n: int, edges: List[List[int]]) -> int:
        from collections import defaultdict
        graph = defaultdict(list)
        for x,y in edges:
            graph[x].append(y)
            graph[y].append(x)
        visited = set()        
        res = 0
        for i in range(n):
            if i not in visited:
                visited.add(i)
                res += 1
                self.dfs(i,graph,visited)        
        return res

2.栈

class Solution:
    def stack(self,i,graph,visited):
        stack = []
        stack.append(i)
        while stack:
            i = stack.pop(-1)
            for t in graph[i]:
                if t not in visited:
                    visited.add(t)
                    stack.append(t)
    def countComponents(self, n: int, edges: List[List[int]]) -> int:
        from collections import defaultdict
        graph = defaultdict(list)
        for x,y in edges:
            graph[x].append(y)
            graph[y].append(x)
        visited = set()        
        res = 0
        for i in range(n):
            if i not in visited:
                visited.add(i)
                res += 1
                self.stack(i,graph,visited)        
        return res

3.bfs

class Solution:
    def bfs(self,i,graph,visited):
        Q = []
        Q.append(i)
        while Q:
            i = Q.pop(0)
            for t in graph[i]:
                if t not in visited:
                    visited.add(t)
                    Q.append(t)
    def countComponents(self, n: int, edges: List[List[int]]) -> int:
        from collections import defaultdict
        graph = defaultdict(list)
        for x,y in edges:
            graph[x].append(y)
            graph[y].append(x)
        visited = set()        
        res = 0
        for i in range(n):
            if i not in visited:
                visited.add(i)
                res += 1
                self.bfs(i,graph,visited)        
        return res

4.并查集

class Solution:
    def countComponents(self, n: int, edges: List[List[int]]) -> int:
        
        def find(x,parent):
            while parent[x] != -1:
                x = parent[x]
            return x
        
        def union_vertices(x,y,parent,rank):
            a=find(x,parent)
            b=find(y,parent)
            if a!=b:
                if rank[a]>rank[b]:
                    parent[b] = a
                elif rank[a]<rank[b]:
                    parent[a] = b
                else:
                    parent[a] = b
                    rank[b]+=1
        
        parent = [-1] * n
        # 用rank来记录高度
        rank = [0] * n
        res=0
        for x,y in edges:
            union_vertices(x, y, parent, rank)
        
        for i in range(n):
            if parent[i]==-1:
                res+=1
        return res

附上并查集basic code

parent = [-1] * 100000
# 用rank来记录高度
rank = [0] * 100000
# 每个集合中的元素个数
count = [1] * 100000

def find(x,parent):
    while parent[x] != -1:
        x = parent[x]
    return x
def union_vertices(x,y,parent,rank,count):
    a=find(x,parent)
    b=find(y,parent)
    if a!=b:
        if rank[a]>rank[b]:
            parent[b] = a
            count[a]+=count[b]
        elif rank[a]<rank[b]:
            parent[a] = b
            count[b]+=count[a]
        else:
            parent[a] = b
            count[b] += count[a]
            rank[b]+=1
res=0
maxsize=0
for i in range(100000):
    if parent[i]==-1:
        res+=1
        maxsize=max(maxsize,count[i])

附:用并查集判断一个无向图中是否存在环

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。

  • Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集合。
  • Union:将两个子集合并成同一个集合。

其实判断一个图是否存在环已经有相应的算法,此文用并查集来判断一个图是否有环。

我们可以用一个一维数组parent[] 来记录子集合。

看下面这个图:

0

|   \                 

|     \

1——2

对每一条边的两个顶点加入集合,发现两个相同的顶点在一个子集合中,就说明存在环。

初始化:parent[n] 的每个元素都为-1,共有n个子集合,表示集合只有当前顶点一个元素

0    1     2

-1   -1   -1

然后逐个处理每条边。

边0-1我们找到两个子集合 0 和1,因为他们在不同的子集合,现在需要合并他们(Union). 把其中一个子集合作为对方的父集合.

0    1   2     <----- 1 成为 0 的 父集合 (1 现在代表集合 {0, 1})

1    -1  -1

边1-2:1属于属于子集合1,2属于子集合2,因此合并他们。

0   1    2     <----- 2 作为 1的父集合 (2 现在代表集合 {0, 1, 2})

1   2   -1

 边0-2: 0是在子集合2,2也是在子集合2, 因为 0->1->2 // 1 是0 父集合 并且  2 是1的父集合 。因此,找到了环   

在判断两个点之间是否有环时,判断它们的父亲节点是否是一个,如果是,则有环

a=find(x,parent)
b=find(y,parent)
if a == b:就找到了环

参考:https://www.cnblogs.com/acm-jing/p/4655513.html

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值