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

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

相关文章

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种

Linux线程之线程的创建、属性、回收、退出、取消方式

《Linux线程之线程的创建、属性、回收、退出、取消方式》文章总结了线程管理核心知识:线程号唯一、创建方式、属性设置(如分离状态与栈大小)、回收机制(join/detach)、退出方法(返回/pthr... 目录1. 线程号2. 线程的创建3. 线程属性4. 线程的回收5. 线程的退出6. 线程的取消7.

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序

Linux下删除乱码文件和目录的实现方式

《Linux下删除乱码文件和目录的实现方式》:本文主要介绍Linux下删除乱码文件和目录的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下删除乱码文件和目录方法1方法2总结Linux下删除乱码文件和目录方法1使用ls -i命令找到文件或目录

Linux在线解压jar包的实现方式

《Linux在线解压jar包的实现方式》:本文主要介绍Linux在线解压jar包的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux在线解压jar包解压 jar包的步骤总结Linux在线解压jar包在 Centos 中解压 jar 包可以使用 u

Jenkins分布式集群配置方式

《Jenkins分布式集群配置方式》:本文主要介绍Jenkins分布式集群配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1.安装jenkins2.配置集群总结Jenkins是一个开源项目,它提供了一个容易使用的持续集成系统,并且提供了大量的plugin满

Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式

《Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式》本文详细介绍如何使用Java通过JDBC连接MySQL数据库,包括下载驱动、配置Eclipse环境、检测数据库连接等关键步骤,... 目录一、下载驱动包二、放jar包三、检测数据库连接JavaJava 如何使用 JDBC 连接 mys

C#读写文本文件的多种方式详解

《C#读写文本文件的多种方式详解》这篇文章主要为大家详细介绍了C#中各种常用的文件读写方式,包括文本文件,二进制文件、CSV文件、JSON文件等,有需要的小伙伴可以参考一下... 目录一、文本文件读写1. 使用 File 类的静态方法2. 使用 StreamReader 和 StreamWriter二、二进

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2

springboot项目打jar制作成镜像并指定配置文件位置方式

《springboot项目打jar制作成镜像并指定配置文件位置方式》:本文主要介绍springboot项目打jar制作成镜像并指定配置文件位置方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录一、上传jar到服务器二、编写dockerfile三、新建对应配置文件所存放的数据卷目录四、将配置文