Leetcode 323.无向连通图中的连通分量个数

Time: 20190903
Type: Medium

题目描述

给定编号从 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
注意:
你可以假设在 edges 中不会出现重复的边。而且由于所以的边都是无向边,[0, 1] 与 [1, 0] 相同,所以它们不会同时在 edges 中出现。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-connected-components-in-an-undirected-graph
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

还是先用最简单的并查集的写法来找到小团伙的个数。因为不是检测环,所以没有必要在Union函数中判断两个点的父亲是不是相同,来决定有没有环。

只需要在连通完毕后,遍历各个节点的大哥是谁,用集合过滤一下,统计一下个数即可。

代码

class UnionFind:
    def __init__(self):
        # 这样初始化是和题意相符的
        self.par = list(range(5001))
    
    def find(self, x):
        if x != self.par[x]:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        self.par[py] = px
              
class Solution:
    def countComponents(self, n: int, edges: List[List[int]]) -> int:
        uf = UnionFind()
        # 先联合
        for e in edges:
            uf.union(e[0], e[1])
        
        # 此时开始判断有多少个子集,用集合过滤
        cnt = 0
        seen = set()
        for i in range(0, n):
            this_par = uf.find(i)
            if this_par not in seen:
                seen.add(this_par)
                cnt += 1
        return cnt

并查集用的是一维数组来表示各个节点的爸爸,初始化时自身是爸爸,上面自己定义了5001个元素,好像和要解的题没有关系,其实是假定题目中的n个结点不超过5001,可以按照真实的结点数传入:

class UnionFind:
    def __init__(self, nums):
        # 这样初始化是和题意相符的
        self.par = list(range(nums))
    
    def find(self, x):
        if x != self.par[x]:
            self.par[x] = self.find(self.par[x])
        return self.par[x]
    
    def union(self, x, y):
        px, py = self.find(x), self.find(y)
        self.par[py] = px
        
        
class Solution:
    def countComponents(self, n: int, edges: List[List[int]]) -> int:
        uf = UnionFind(n)
        # 先联合
        for e in edges:
            uf.union(e[0], e[1])
        
        # 此时开始判断有多少个子集
        cnt = 0
        seen = set()
        for i in range(0, n):
            this_par = uf.find(i)
            if this_par not in seen:
                seen.add(this_par)
                cnt += 1
        print(seen)
        return cnt

再写一遍非递归版本的find:

class Solution:
    def countComponents(self, n: int, edges: List[List[int]]) -> int:
        class UnionFind:
            def __init__(self, nums):
                self.par = list(range(nums))
            
            def find(self, x):
                r = x
                while r != self.par[r]:
                    r = self.par[r]
                # 路径压缩
                i = x
                while i != r:
                    tmp = self.par[i]
                    self.par[i] = r
                    i = tmp
                return r
                
            def union(self, x, y):
                xr = self.find(x)
                yr = self.find(y)
                self.par[yr] = xr
                
        uf = UnionFind(n)
        
        for edge in edges:
            uf.union(edge[0], edge[1])
        
        # 开始统计小团伙的数量
        count = 0
        seen = set()
        
        for i in range(n):
            p = uf.find(i)
            if p not in seen:
                count += 1
                seen.add(p)
        return count

END.

你可能感兴趣的:(LeetCode)