• leetcode547朋友圈(并查集)


    这是我和yzc大佬在数据结构课上写的题,我:并查集我一点概念都没有。 yzc大佬:你做做试试。
    然后我就开了这道题。我写了十分钟,妈的这个并查集怎么写,感觉只会DFS。然后yzc大佬接手,五分钟后,AC。然后我盯着他的代码看了半天没看懂。
    下课后,丫的突然开窍,好简单,我可以!
    题目是这样的

    班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。
    
    给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。
    
    示例 1:
    
    输入: 
    [[1,1,0],
     [1,1,0],
     [0,0,1]]
    输出: 2 
    说明:已知学生0和学生1互为朋友,他们在一个朋友圈。
    第2个学生自己在一个朋友圈。所以返回2

    然后并查集也有两种思路,一种复杂度是恒为O(N)O(N),另一种复杂度是O(1)O(logN)O(1)-O(logN),我两种都是实现了一下。
    先说一下我的并查集解题思路,并查集是这样的,先寻找有关系的两个对象,每找到一组关系,然后查找两个对象分别属于的集合,若不是同一个集合,那么就合并两个集合。以此迭代。

    1. 线性并查集,代码如下
    class Solution(object):
        def findCircleNum(self, M):
            """
            :type M: List[List[int]]
            :rtype: int
            """
            #构造初始并查集
            li = [i for i in range(len(M))]
            for j in range(len(M)):
                for k in range(len(M)):
                    if M[j][k] == 1 and j != k:
                    #这里是寻找到了有关系的两个对象,然后开始将其中一个集合的下标的值都改成另一个集合下标的值
                        for num in range(len(li)):
                            if li[num] == min(li[j],li[k]):
                                li[num] = max(li[j],li[k])    
            return len(set(li))
    
    1. 非线性并查集
    class Solution(object):
        def __init__(self):
            self.li = [i for i in range(205)]
        def findCircleNum(self, M):
            """
            :type M: List[List[int]]
            :rtype: int
            """
            for i in range(len(M)):
                for j in range(len(M)):
                    if M[i][j] == 1 and i != j:
                        self.merge(i, j)
        
        def merge(self, i, j):
            fi = self.find(i)
            fj = self.find(j)
            if fi != fj:
                self.li[fi] = self.li[fj]
    
        def find(self, x):
            while self.li[x] != x:
                x = self.li[x]
            return x
    

    这里重点写一下非线性并查集

    1. 首先我们创建初始并查集
    朋友圈 0 1 2 3
    下标 0 1 2 3
    1. 然后我们开始寻找有关系的两个同学
    2. 找到两个同学有关系(M[i][j]=1 and i != j)后,我们开始需要开始合并这两个朋友圈merge(),再合并朋友圈是,我们需要找到这两个朋友圈分别是几号朋友圈,这里就用到的定义的find()函数,我们使用递归的方法得到根节点(也就是他们的朋友圈序号),然后对比他们得到的朋友圈序号,将其中一个的序号进行修改。
    3. 最后查找我们的得到的并查集序列,查找在人数范围内总共有几个朋友圈。(查找li[i] == i的数量)。
      这就是效率较高的并查集的做法。
  • 相关阅读:
    算法导论 第二部分——排序和顺序统计量
    算法导论——第一部分——基础知识
    liunx中的进程与线程
    vector中pair的排序方法
    sql 入门经典(第五版) Ryan Stephens 学习笔记 第五部分: 性能调整
    sql 入门经典(第五版) Ryan Stephens 学习笔记  第四部分:建立复杂的数据库查询/
    Object C学习笔记1-基本数据类型说明
    Objective-C(生命周期)
    从 React 的组件更新谈 Immutable 的应用
    React性能优化总结(转)
  • 原文地址:https://www.cnblogs.com/yfc0818/p/11072610.html
Copyright © 2020-2023  润新知