并查表(认老大的区分方式)

2023-10-21 04:10
文章标签 方式 区分 查表 老大

本文主要是介绍并查表(认老大的区分方式),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、并查表的用处
  • 二、并查表的构成
  • 三、例题剖析
    • 为什么要使用并查表来解决此题?
  • 提升


一、并查表的用处

一般由于检测图的连通性问题。给你一幅图,和图中两个结点,请问这两个结点是否相连通?或者检测该图中是否有环。当然还可解决其他问题。

二、并查表的构成

由find函数,join函数,以及对应的集合的代表结点数组构成。

像黑社会这种组织,都是老大说了算,老大的手下都是跟着老大做事,可以这么说老大一定程度上是手下的代表,一个老大代表了他所有的手下。将元素都归于集合中,这就是并查表的主要思想。一个人也可以是一个黑社会团体哦
如果对集合概念了解的,可以理解为,将一个个结点(手下)放入到不同的集合(黑社会团体)中,对应的集合的代表结点数组 表示不同的集合(用集合中的一个元素代表该集合)(老大代表了黑社会团体),join函数 的作用是将结点放入到集合中,亦或者将两个集合并操作(两个黑社会黑吃黑,一个黑社会吞并另一个黑社会)。find函数 的作用是给一个结点,找到该结点对应集合的代表结点。(给一个手下找到他所属黑社会的老大)

三、例题剖析

  1. 冗余连接
    在本问题中, 树指的是一个连通且无环的无向图。
    输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, …, N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。
    结果图是一个以边组成的二维数组。每一个边的元素是一对[u, v] ,满足 u < v,表示连接顶点u 和v的无向图的边。
    返回一条可以删去的边,使得结果图是一个有着N个节点的树。如果有多个答案,则返回二维数组中最后出现的边。答案边 [u, v] 应满足相同的格式 u < v。

题目来源:leetcode 684 冗余连接
题目要求可简化为,该无向图中含有一环,请找出该环中一个连接。

解该题的方法有很多,这里只写出使用并查表的解决方案。
举一个例子:
假设输入是:

[[1,4],[3,4],[1,3],[1,2],[4,5]]

可视化的图
在这里插入图片描述
很明显,1 - 4 - 3 是一个环,按道理来讲, 返回[1 , 4],[3, 4] 或者 [1, 3] 都可,而题目中要求 如果有多个答案,则返回二维数组中最后出现的边说明只需要返回[1, 3]。

接下来推断:
我们先创建一个数组 假设索引从1开始,不是0,该数组的索引是指对应的结点,而其值就是结点所属的集合。集合的表示方法用集合元素中的首项来表示该集合

        # 声明一个数组root_list = [i for i in range(1, len(edges) + 1)]

可以看出一开始每一个结点的结合都只有自己。结点1所属集合只有1一个元素,结点2所属集合只含2一个元素…

find函数的实现

“”“参数:tar 	图中的一个结点的值nums	记录老大数组返回:该结点对应的集合,并返回该集合代表的结点
”“”def find(tar, nums):while tar != nums[tar]:tar = nums[tar]return tar

主函数和join函数的实现:

 for item in edges:# 找到两边结点所属的集合set_1 = find(item[0], root_list)set_2 = find(item[1], root_list)# 如果边开头和边结尾的元素都是同一个集合,说明一定是一个环if set_1 == set_2:return item# 当发现双方所含的集合不一样的时候,选择其中一个集合,另一个集合加入该集合。else:root_list[set_2] = set_1

步骤如下:
root_list:[1, 2, 3, 4, 5]

第一步:
读取[1, 4]
1的集合只含1,4的集合只含4。
发现所属集合不一样,4的集合加入1的集合
所以root_list变化为:[1, 2, 3, 1, 5]

第二步:
读取[3, 4]
3所属集合有3,4所属集合有1,4(用1表示该集合)
发现集合不一样, 4所属的结合加入3的集合中 (4所属的集合的代表是 1,所以数组中第一位的值变为3,说明1集合和3集合合并,那么3集合所包含的元素就有3,1,4)
所以root_list变化为:[3, 2, 3, 1, 5]

第三步:
读取[1, 3]
发现1和3的属于同一个集合,返回该数组[1, 3]为所求。

可能会有疑问,为什么第二步最后的root_list变更是[3, 2, 3, 1, 5],而不是[3, 2, 3, 3, 5]呢?
1,3,4同属于一个集合中为什么root_list会不一样?当然我们也是想一样的,因为这样的话,find函数就不需要了,直接访问root_list就好了,其索引对应的值就是所属集合的代表。可是我们很难做到,或者说要花费沉重的代价去实现。所以find函数,帮我们节省这些操作。当[3, 2, 3, 1, 5]传入find函数,想找到第四项所属的集合的代表,访问第四项,对应的值1,然后判断1跟索引值4不相同,说明1不是一个集合的代表,然后将1作为索引,访问第一项,第一项的值为3,判断跟索引1不相同,说明3不是一个集合的代表,然后将3作为索引,访问第三项,发现索引值3和其索引对应的值也是3,相同,说明3是一个集合的代表。推出4所属的集合的代表为3。

明白以上操作后,总代码仅仅只是将索引调整了一下,因为索引从0开始:


class Solution(object):def findRedundantConnection(self, edges):""":type edges: List[List[int]]:rtype: List[int]"""def find(tar, nums):while tar != nums[tar - 1]:tar = nums[tar - 1]return tar# 声明一个结点数组root_list = [i for i in range(1, len(edges) + 1)]for item in edges:print("  item 0 :", item[0], "  item 1 :", item[1])set_1 = find(item[0], root_list)set_2 = find(item[1], root_list)print(set_1, set_2)print(root_list)if set_1 == set_2:return item# 进行合并else:root_list[set_2 - 1] = set_1if __name__ == '__main__':test_class = Solution()print(test_class.findRedundantConnection([[1, 4], [3, 4], [1, 3], [1, 2], [4, 5]]))

为什么要使用并查表来解决此题?

假设我们要解决的问题是,给定两个结点,判断该结点是否连通。使用并查集的思路是:将连通第一个结点的所有结点都放入一个集合中,然后看看,另一个结点是否也在该集合中,如果存在就说明连通,不存在就不连通。回到该题,我们将互相连接的元素都放入一个集合中,如果发现有一条边的两头结点都是同一个集合的,说明这条边尚未连接时,这两个结点已经连接起来了,现在再加上这条边,这种情况只有可能是环。


提升

  当发现双方所含的集合不一样的时候,选择其中一个集合,另一个集合加入该集合。

这里有其实应该选择将一个小的集合,加入到一个大的集合。 而不是随机的选择,或者固定左集合往右集合合并,这就是路径压缩算法的核心思想。

这篇关于并查表(认老大的区分方式)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/251821

相关文章

Jsoncpp的安装与使用方式

《Jsoncpp的安装与使用方式》JsonCpp是一个用于解析和生成JSON数据的C++库,它支持解析JSON文件或字符串到C++对象,以及将C++对象序列化回JSON格式,安装JsonCpp可以通过... 目录安装jsoncppJsoncpp的使用Value类构造函数检测保存的数据类型提取数据对json数

Redis事务与数据持久化方式

《Redis事务与数据持久化方式》该文档主要介绍了Redis事务和持久化机制,事务通过将多个命令打包执行,而持久化则通过快照(RDB)和追加式文件(AOF)两种方式将内存数据保存到磁盘,以防止数据丢失... 目录一、Redis 事务1.1 事务本质1.2 数据库事务与redis事务1.2.1 数据库事务1.

Linux磁盘分区、格式化和挂载方式

《Linux磁盘分区、格式化和挂载方式》本文详细介绍了Linux系统中磁盘分区、格式化和挂载的基本操作步骤和命令,包括MBR和GPT分区表的区别、fdisk和gdisk命令的使用、常见的文件系统格式以... 目录一、磁盘分区表分类二、fdisk命令创建分区1、交互式的命令2、分区主分区3、创建扩展分区,然后

Linux中chmod权限设置方式

《Linux中chmod权限设置方式》本文介绍了Linux系统中文件和目录权限的设置方法,包括chmod、chown和chgrp命令的使用,以及权限模式和符号模式的详细说明,通过这些命令,用户可以灵活... 目录设置基本权限命令:chmod1、权限介绍2、chmod命令常见用法和示例3、文件权限详解4、ch

Java中的密码加密方式

《Java中的密码加密方式》文章介绍了Java中使用MD5算法对密码进行加密的方法,以及如何通过加盐和多重加密来提高密码的安全性,MD5是一种不可逆的哈希算法,适合用于存储密码,因为其输出的摘要长度固... 目录Java的密码加密方式密码加密一般的应用方式是总结Java的密码加密方式密码加密【这里采用的

Java中ArrayList的8种浅拷贝方式示例代码

《Java中ArrayList的8种浅拷贝方式示例代码》:本文主要介绍Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅... 目录引言什么是浅拷贝?ArrayList 浅拷贝的重要性方法一:使用构造函数方法二:使用 addAll(

Mycat搭建分库分表方式

《Mycat搭建分库分表方式》文章介绍了如何使用分库分表架构来解决单表数据量过大带来的性能和存储容量限制的问题,通过在一对主从复制节点上配置数据源,并使用分片算法将数据分配到不同的数据库表中,可以有效... 目录分库分表解决的问题分库分表架构添加数据验证结果 总结分库分表解决的问题单表数据量过大带来的性能

SpringBoot项目引入token设置方式

《SpringBoot项目引入token设置方式》本文详细介绍了JWT(JSONWebToken)的基本概念、结构、应用场景以及工作原理,通过动手实践,展示了如何在SpringBoot项目中实现JWT... 目录一. 先了解熟悉JWT(jsON Web Token)1. JSON Web Token是什么鬼

在C#中合并和解析相对路径方式

《在C#中合并和解析相对路径方式》Path类提供了几个用于操作文件路径的静态方法,其中包括Combine方法和GetFullPath方法,Combine方法将两个路径合并在一起,但不会解析包含相对元素... 目录C#合并和解析相对路径System.IO.Path类幸运的是总结C#合并和解析相对路径对于 C

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初