【LeetCode】十六、并查集

文章目录

  • 1、并查集Union Find
  • 2、并查集find的优化:路径压缩 Quick find
  • 3、并查集union的优化:权重标记
  • 4、leetcode200:岛屿数量
    • 解法一:DFS

1、并查集Union Find

并查集,一种树形的数据结构,处理不相交的两个集合的合并与查询问题。

【参考:📕经典解释】

引用上面文章的经典解释并查集:

  • 一个集合就像一个江湖门派,他们有一个教主(代表元),集合中每个元素只需要记住自己的上级,而不是教主
  • find即查询某个元素的代表元(教主)
  • union即把两个门派(集合),合并成一个,认一个教主

在这里插入图片描述

例子:

在这里插入图片描述

查find(x)

有个数组array,长度为10,若array[1] = 6,说明1号元素的上级是6号元素。array[6] = 6,说明6号元素的上级是6号元素,即6号是教主。并查集的查:find(x),即找x元素的教主

public int find(int x ) {
	// 如果x位置的值,等于x,说明x就是教主
	if (x == array[x]) {
		return array[x];
	}
	// 如果不是,查x位置的值的上级
	return find(array[x]);
}

也可不用递归:

public int find(int x ) {
	while(x != array[x]) {
		// 查x位置的元素自己的上级
		x = array[x];
	}
	return x;
}

并union(x,y)

两个集合合并,或者说两个门派合并,看似改动很大,其实只要让一个门派的教主给另一个门派的教主当上级即可。因为只关注两个集合的连通性。

// 传入两个门派的元素
public void union(int x, int y) {
	//查教主
	int rootX = find(x);
	int rootY = find(y);
	if (rootX != rootY) {
		// 让Y门派的教主当X门派教主的上级
		array[rootX] = rootY;
	}
}

如下树形,

在这里插入图片描述

对应的数组:数组索引代表元素,数组的值,代表这个位置的元素的上级

在这里插入图片描述
在这里插入图片描述
合并后,比如让第一个集合的教主做合并后新集合的教主:5号的上级不再是自己,变成了1

在这里插入图片描述

2、并查集find的优化:路径压缩 Quick find

用开头引用文章的形象例子,现在要做的就是,防止树形结构过于深,导致查询效率变低,将结果压缩成,只要查一次,就能知道教主是谁:

在这里插入图片描述

总之一句话,防止树太高,期待右边,而不是左边

在这里插入图片描述

想实现这个效果,可以:查询到x元素的根节点(教主)后,直接将x元素的上级改成根节点。

public int QuickFind(int x ) {
	// 如果x位置的值,等于x,说明x就是教主
	if (x == array[x]) {
		return array[x];
	}
	// 如果不是,查x位置的值的上级,等递归回退的时候,把x的上级改成根节点
	return array[x] = find(array[x]);
}

也就是说,第一次find元素x,是没有压缩路径的,第二次才是优化后的效果

3、并查集union的优化:权重标记

和find优化属于同一思想,union两个集合时,防止树过高,比如合并:

在这里插入图片描述
如果这么连,树过高:

在这里插入图片描述
比较两棵树的高度,左边为2,右边为3,因此,高的树原地不动,继续做老大,低的树靠过去,union后的效果:

在这里插入图片描述

核心思想:

在这里插入图片描述

整体代码如下,带权重的union参考:

public class UnionFind {

	const int  N=1005					//指定并查集所能包含元素的个数(由题意决定)
	int pre[N];     					//存储每个结点的前驱结点的数组 
	int rank[N];    					//树的高度,权重
	
	void init(int n) {     				//初始化函数,对录入的 n个结点进行初始化 
	    for(int i = 0; i < n; i++){
	        pre[i] = i;     			//每个结点的上级都是自己 
	        rank[i] = 1;    			//每个结点构成的树的高度为 1 
	    } 
	}

	int find(int x) {
     	//查找结点 x的根结点 
		if (pre[x] == x) { 
			return x ;					//递归出口:x的上级为 x本身,则 x为根结点 
		}  		
	    return find(pre[x]); 			//递归查找 
	} 
	 
	int findQucik(int x) {     			//改进查找算法:完成路径压缩,将 x的上级直接变为根结点,那么树的高度就会大大降低 
	    if (pre[x] == x) {
	    	return x;					//递归出口:x的上级为 x本身,即 x为根结点 
	    }
	    return pre[x] = find(pre[x]);   //此代码相当于先找到根结点 rootx,然后 pre[x]=rootx 
	} 
	
	bool isSame(int x, int y) {     	//判断两个结点是否连通 
	    return find(x) == find(y);  	//判断两个结点的根结点(即代表元)是否相同 
	}
	
	void union(int x,int y) {
	    int rootx = find(x);			//寻找 x的代表元
	    int rooty = find(y);			//寻找 y的代表元
	    if(rootx != rooty) {			//如果 x和 y的代表元一致,说明他们共属同一集合,则不需要合并
		    if(rank[rootx] > rank[rooty]) {		//如果 x的高度大于 y,则令 y的上级为 x
		    	pre[rooty] = rootx;
		    } else if (rank[rootx] < rank[rooty]) {
		    	pre[rootx] = rooty;		//让 x的上级为 y
		    } else {
		    	pre[rooty] = rootx;	    								
		        rank[rootx] += 1;				//如果 x的高度和 y的高度相同,则令 y的高度加1					
			}
		}
	}
}

4、leetcode200:岛屿数量

在这里插入图片描述

关于题目的理解,1为陆地,0为水,二维网格外都是水两个示例中的陆地如下:

在这里插入图片描述

解法一:DFS

以示例二来分析,从二维网格的第一个元素开始遍历,找到1后,将其改为0(同化),并将其水平或竖直方向上相邻的1也改为0,如下

在这里插入图片描述
递归,将找到的1 水平或竖直方向上相邻的1 水平或竖直方向上相邻的1 再次改为0,结果result + 1,如下:

在这里插入图片描述
继续往下遍历,找到了第二个1(说明这又是一块新的岛屿,因为前面同化时,没有把它变成0,即它和前一块岛屿不挨着) ,继续将其同化成0,并递归把其水平或竖直方向上相邻的1也全都改为0,结果result + 1:

在这里插入图片描述
继续往下遍历,找到了第三个1,又是一块新的岛屿,继续同化成0,递归把其水平或竖直方向上相邻的1也全都改为0,结果result + 1

在这里插入图片描述
继续遍历,没1了,结束,最终result为3。代码实现:


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/803581.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何在excel表中实现单元格满足条件时整行变色?

可以试试使用条件格式&#xff1a; 一、条件格式 所谓“自动变色”就要使用条件格式。 先简单模拟数据如下&#xff0c; 按 B列数字为偶数 为条件&#xff0c;整行标记为蓝色背景色。 可以这样设置&#xff1a; 先选中1:10行数据&#xff0c;在这里要确定一下名称栏里显示…

DNS查询过程

DNS&#xff08;域名系统&#xff0c;Domain Name System&#xff09;是一个用于将域名和IP地址相互映射的系统。当你在浏览器中输入一个网址时&#xff0c;浏览器会通过DNS查询过程来找到对应的IP地址&#xff0c;以便能够连接到目标服务器。其查询过程一般通过以下步骤&#…

Apple Vision Pro 和其商业未来

机器人、人工智能相关领域 news/events &#xff08;专栏目录&#xff09; 本文目录 一、Vision Pro 生态系统二、Apple Vision Pro 的营销用例 随着苹果公司备受期待的进军可穿戴计算领域&#xff0c;新款 Apple Vision Pro 承载着巨大的期望。 苹果公司推出的 Vision Pro 售…

MySQL数据库慢查询日志、SQL分析、数据库诊断

1 数据库调优维度 业务需求&#xff1a;勇敢地对不合理的需求说不系统架构&#xff1a;做架构设计的时候&#xff0c;应充分考虑业务的实际情况&#xff0c;考虑好数据库的各种选择(读写分离?高可用?实例个数?分库分表?用什么数据库?)SQL及索引&#xff1a;根据需求编写良…

Qt窗口程序整理汇总

到今日为止&#xff0c;通过一个个案例的实验&#xff0c;逐步熟悉了 Qt6下 窗体界面开发的&#xff0c;将走过的路&#xff0c;再次汇总整理。 Qt Splash样式的登录窗https://blog.csdn.net/castlooo/article/details/140462768 Qt实现MDI应用程序https://blog.csdn.net/cast…

数据库课设---学生宿舍管理系统(sql server+C#)

1.引言 1.1 内容及要求 设计内容&#xff1a;设计学生宿舍管理系统。 设计要求&#xff1a; &#xff08;1&#xff09;数据库应用系统开发的需求分析&#xff0c;写出比较完善系统功能。 &#xff08;2&#xff09;数据库概念模型设计、逻辑模型设计以及物理模型设计。 …

【数学建模】——多领域资源优化中的创新应用-六大经典问题解答

目录 题目1&#xff1a;截取条材 题目 1.1问题描述 1.2 数学模型 1.3 求解 1.4 解答 题目2&#xff1a;商店进货销售计划 题目 2.1 问题描述 2.2 数学模型 2.3 求解 2.4 解答 题目3&#xff1a;货船装载问题 题目 3.1问题重述 3.2 数学模型 3.3 求解 3.4 解…

JS爬虫实战之极验四代

极验四代滑块验证码 一、目标网站说明二、流程步骤1. 逆向步骤一般分为&#xff1a;2. 接口确认1- 确认流程2- 获取verify的参数3- 构建requests验证verify的参数4- 锁定secode参数的作用 ok&#xff0c;让我们去获取verify接口中的响应&#xff01;&#xff01;&#xff01; 3…

el-table表格操作列错行处理

解决方法&#xff1a; <style>::v-deep .el-table th.el-table__cell > .cell {white-space: nowrap !important;} </style>

【C++航海王:追寻罗杰的编程之路】智能指针

目录 1 -> 为什么需要智能指针&#xff1f; 2 -> 内存泄漏 2.1 ->什么是内存泄漏&#xff0c;以及内存泄漏的危害 2.2 -> 内存泄漏分类 2.3 -> 如何避免内存泄漏 3 -> 智能指针的使用及原理 3.1 -> RAII 3.2 -> 智能指针的原理 3.3 -> std…

Kafka Producer发送消息流程之Sender发送线程和在途请求缓存区

文章目录 1. Sender发送数据1. 发送数据的详细过程&#xff1a;2. 关键参数配置 2. 在途请求缓存区 1. Sender发送数据 Sender线程负责将已经在RecordAccumulator中准备好的消息批次发送到Kafka集群。虽然消息在RecordAccumulator中是按照分区组织的&#xff0c;但Sender线程在…

【C++】类和对象的基本概念与使用

本文通过面向对象的概念以及通俗易懂的例子介绍面向对象引出类和对象。最后通过与之有相似之处的C语言中的struct一步步引出C中的类的定义方式&#xff0c;并提出了一些注意事项&#xff0c;最后描述了类的大小的计算方法。 一、什么是面向对象&#xff1f; 1.面向对象的概念 …

基于python的图像去水印

1 代码 import cv2 import numpy as npdef remove_watermark(image_path, output_path):# 读取图片image cv2.imread(image_path)# 转换为灰度图gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 使用中值滤波去除噪声median_filtered cv2.medianBlur(gray, 5)# 计算图像的梯…

Ambari Hive 创建函数无权限

作者&#xff1a;櫰木 1、创建udf函数 参考文档&#xff1a;https://blog.csdn.net/helloxiaozhe/article/details/102498567 如果已经编写好&#xff0c;请使用自己的。如果没有请参考以上链接进行udf函数编写。 2、创建函数遇到的问题 由于集群开启了kerberos&#xff0…

常用的点云预处理算法

点云预处理是处理点云数据时的重要部分&#xff0c;其目的是提高点云数据的质量和处理效率。通过去除离群点、减少点云密度和增强特征&#xff0c;可以消除噪声、减少计算量、提高算法的准确性和鲁棒性&#xff0c;从而为后续的点云处理和分析步骤&#xff08;如配准、分割和重…

[超级详细系列]ubuntu22.04配置深度学习环境(显卡驱动+CUDA+cuDNN+Pytorch)--[3]安装cuDNN与Pytorch

本次配置过程的三篇博文分享分别为为&#xff1a; [超级详细系列]ubuntu22.04配置深度学习环境(显卡驱动CUDAcuDNNPytorch)--[1]安装显卡驱动 [超级详细系列]ubuntu22.04配置深度学习环境(显卡驱动CUDAcuDNNPytorch)--[2]安装Anaconda与CUDA [超级详细系列]ubuntu22.04配置深…

使用windows批量解压和布局ImageNet ISLVRC2012数据集

使用的系统是windows&#xff0c;找到的解压命令很多都linux系统中的&#xff0c;为了能在windows系统下使用&#xff0c;因此下载Git这个软件&#xff0c;在其中的Git Bash中使用以下命令&#xff0c;因为Git Bash集成了很多linux的命令&#xff0c;方便我们的使用。 ImageNe…

Python: 一些python和Java不同的基础语法

文章目录 1. 数据类型2. 字符串的引用3. 字符串拼接4. Python中的报错5. Python中的输入语句(input)6. 运算符(**和//)7. 除法运算8. 注释方法: #或者三引号9. Python中的比较10. Java中用and, or, not代替逻辑运算符11. 多元赋值12. Python不支持自增自减操作13. 在Python中, …

jenkins 使用教程

1. 安装最新长期稳定版 2.426.1 Redhat Jenkins Packages sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo --no-check-certificate sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key yum insta…

Oracle线上执行SQL特别慢的原因分析

一、背景&#xff1a; 线上反馈一张表select * from table where idxxx语句执行特别慢&#xff0c;超过60s超时不能处理&#xff0c;第一直觉是索引失效了&#xff0c;开始执行创建索引语句create index index_name on table() online。但是执行了超过20分钟索引还没有创建成功…