【C++】并查集

news2024/11/24 20:39:42

并查集这个数据结构本身并不难,其主要是提供一个思路,方便我们编写图的代码,和一些OJ题

文章目录

  • 1.什么是并查集?
  • 2.思路
    • 2.1 合并集合
    • 2.2 压缩路径
  • 3.代码
  • 4.OJ题
    • 4.1 剑指 Offer II 116. 省份数量
    • 4.2 等式方程的可满足性

1.什么是并查集?

并查集是多个独立集合的合集,用于表示数据之间的关系。

比较生动的例子,就是我们生活中的朋友圈(不是wx的那个啊)

  • 张三和李四是好朋友,那么他们就构成了一个集合A
  • 王舞和王陆是好朋友,那么他们也构成了一个集合B
  • 此时,王舞突然认识了李四,这时候,就可以把A和B合并成一个集合

推而广之,一个并查集中可以有多个这样的集合,多个朋友圈。

  • 并查集中的每一个集合是用多叉树来表示的

2.思路

并查集的思路并不难,给定一个数组的大小(需要在另外的地方管理编号)创建一个并查集

下标即为数据的编号

  • 设定元素的初始值都是-1
  • 如果下标1和3为一个集和,那就把3的元素(初始值-1)加到1处,即1的元素为-2;再把3的元素设置为1的下标,即3的元素为1
  • 依此类推,最终只要下标所对应元素不为负数,那么这个下标就是一个集和的成员
  • 如果为负数,那么就是一个集合的根,且元素为这个集和中成员的个数(绝对值)

如图所示,下标678所对应元素为0,代表它们属于以下标0为根的一个集合。而下标0处的元素为-4,代表这个集合里面有4个元素

image-20221201150318228

2.1 合并集合

如果我们需要合并一个集合,以上图中的0集合和1集合为例。我们只需要将1集合的元素-3加到0集合上,再把1集合的元素改成0即可

此时的树就会是这样的👇

image-20221201151418278

2.2 压缩路径

当节点很多,集合可能会出现路径长度过大的情况。这时候我们就需要进行路径的压缩

其方法很简单。遍历整个并查集,将同一集合的子节点改成相同的父亲即可

image-20221201152737608

这样在向上找集合的根时,无须跳转多次,一次就能找到。

但由于并查集的访问是依靠数组下标实现的随机访问,时间复杂度为O(1),只有数据样本量极大的时候,这么做才能有效果


3.代码

相比于其他数据结构复杂的实现,并查集的实现就简单多了。主要的函数只有几个,可以通过封装vector来实现

class UnionFindSet {
public:
	UnionFindSet(const int sz)
		:_set(sz,-1)//调用vector构造函数,初始化sz个-1
	{}

	void Union(int x, int y)//设置x和y为一个集合
	{
		int r1 = FindRoot(x);
		int r2 = FindRoot(y);

		if (r1 != r2)//不在一个集和中
		{
			_set[r1] += _set[r2];
			_set[r2] = r1;
		}
	}

	int FindRoot(int n)//找这个集合的根
	{
		while (_set[n] >= 0)
		{
			n = _set[n];
		}
		return n;//负数的时候为根
	}

	bool isUnion(int x,int y)//判断是否在一个集合中
	{
		return FindRoot(x) == FindRoot(y);
	}

	int UnionSZ()//返回有几个集合
	{
		int count = 0;
		for (int i = 0; i < _set.size(); i++)
		{
			if (_set[i] < 0)
			{
				count++;
			}
		}
		return count;
	}
private:
	vector<int> _set;//用来存放对应关系
};

这里没有写压缩路径的代码,其实也就是一个遍历搞定的事😂

4.OJ题

4.1 剑指 Offer II 116. 省份数量

剑指 Offer II 116. 省份数量

image-20221201155824404

有了并查集,这道题就非常简单。最重要的是思路。我们无须现场造一个轮子,只需要写好找根函数,用一个数组就能实现一个简单的并查集

class Solution {
public:
    int FindRoot(const vector<int>& v,int n)
    {
        int prev = n;//初始下标
        while(v[prev]>=0)//它的父亲下标
        {
            prev=v[prev];//如果不为负数,那就还是需要往前找
        }
        return prev;
    }

    int findCircleNum(vector<vector<int>>& isConnected) 
    {
        vector<int> v(isConnected.size(),-1);
        for(int i=0;i<isConnected.size();i++)
        {
            for(int j=0;j<isConnected[i].size();j++)
            {
                if(isConnected[i][j]==1)//为1代表是一个集合中的元素
                {
                    int root1 = FindRoot(v,i);
                    int root2 = FindRoot(v,j);
                    if(root1!=root2)
                    {
                        v[root1] += v[root2];
                        v[root2] = root1;
                    }
                }
            }
        }

        int count = 0;
        for(int i=0;i<v.size();i++)
        {
            if(v[i]<0)
            {
                count++;
            }
        }

        return count;
    }
};

image-20221201160014014

4.2 等式方程的可满足性

990.等式方程的可满足性

image-20221201200826342

这道题和上面那一道差不多,只不过把省份换成了字母之间的关系

class Solution {
public:
    int FindRoot(const vector<int>& v,int n)
    {
        int prev = n;//初始下标
        while(v[prev]>=0)//它的父亲下标
        {
            prev=v[prev];//如果不为负数,那就还是需要往前找
        }
        return prev;
    }

    bool equationsPossible(vector<string>& equations) {
        vector<int> v(26,-1);//因为题目给的都是小写字母,直接建立26个小写字母的映射表
        for(int i=0;i<equations.size();i++)
        {
            int root1 = FindRoot(v,equations[i][0]-'a');//第一个字母
            int root2 = FindRoot(v,equations[i][3]-'a');//第二个字母
            if(equations[i][1]=='=')//代表等于
            {
                if(root1!=root2)
                {//设置为一个集合中的元素
                    v[root1] += v[root2];
                    v[root2] = root1;
                }
            }
            else//不等于
            {
                if(root1==root2)
                {
                    //如果不等于的同时,根还相同
                    //说明是同一个集合,不符合题意
                    return false;
                }
            }
        }

        //还需要遍历第二遍,避免漏网之鱼
        for(int i=0;i<equations.size();i++)
        {
            int root1 = FindRoot(v,equations[i][0]-'a');//第一个字母
            int root2 = FindRoot(v,equations[i][3]-'a');//第二个字母
            if(equations[i][1]=='!')//不等于
            {
                if(root1==root2)
                {
                    //如果不等于的同时,根还相同
                    //说明是同一个集合,不符合题意
                    return false;
                }
            }
        }

        return true;
    }
};

image-20221201200909339

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高精度工厂人员定位,打造数字化智慧工厂

工厂人员定位&#xff0c;通过对工业厂区人员、物资、车辆进行精准的定位&#xff0c;实现对人员、物资、车辆的智慧管控&#xff0c;从而实现工厂安全生产管理智能化。 人工智能的推广使得工厂的生产效率不断提升&#xff0c;企业对安全生产和降本增效的需求也越来越大。高精度…

跨境电商迎来销售旺季,APS计划排产帮助企业提升生产效率

根据报道称&#xff0c;我国跨境电商的进出口规模5年来增长了近10倍&#xff0c;为了商品能够顺利“出海”&#xff0c;不少物流企业开辟了新的物流专线。 据海关统计&#xff0c;我国跨境电商进出口规模5年增长近10倍。为了保障商品顺利“出海”&#xff0c;今年&#xff0c;不…

Tableau 入门系列之各种图形绘制

文章目录What熟悉Tableau绘制各种图形柱状图 &#x1f4ca;折线图&#x1f4c8;饼图文字云气泡图热图突出显示图筛选器参考线地图制作DashboardWhat Tableau 是一个可视化分析平台&#xff0c;它改变了我们使用数据解决问题的方式&#xff0c;使个人和组织能够充分利用自己的数…

虚拟内存系统【页面置换算法】

页面置换算法&#x1f4d6;1. 最优页面置换算法(OPT)&#x1f4d6;2. 先入先出置换算法(FIFO)&#x1f4d6;3. 随机(Random)&#x1f4d6;4. 最近最少使用的置换算法(LRU)&#x1f4d6;5. 近似LRU 时钟页面置换算法&#x1f4d6;6. 最不常用算法&#x1f4d6;7. 考虑脏页在虚拟…

CleanMyMac X2022苹果电脑专业清理Mac加速器软件

CleanMyMac X2023最新免费版苹果电脑专业清理软件&#xff0c;对于Mac电脑用户来说&#xff0c;Cleanmymac X是一款再熟悉不过的电脑清理软件&#xff0c;它是由苹果认证并对外承认的一款第三方清理软件&#xff0c;几乎有95%的Mac用户都会安装并使用&#xff0c;Cleanmymac X究…

代码随想录——栈与队列

232.用栈实现队列 力扣题目链接 使用栈实现队列的下列操作&#xff1a; push(x) – 将一个元素放入队列的尾部。 pop() – 从队列首部移除元素。 peek() – 返回队列首部的元素。 empty() – 返回队列是否为空。 示例: MyQueue queue new MyQueue(); queue.push(1); queu…

如何使用qemu调试内核

文件系统 调试内核需要一个基本的文件系统&#xff0c;我们可以使用简单的 ramdisk来作为这个文件系统&#xff0c;如果&#xff0c;需要测试一些其它应用程序&#xff0c;我们还需要创建一个大一点根文件系统。 Ramdisk 也就是内核启动时的initrd.img&#xff0c;可以使用b…

iOS创建苹果证书、制作p12证书流程

一、创建Certificates 1、在苹果开发者后台点击右上角【Account】进入以下界面&#xff0c;然后点击【Certificates, Identifiers & Profiles】 2、进入以下界面后点击【Create a certificate】 3、然后选择证书类型&#xff0c;Apple Development&#xff08;开发者证书…

Oracle中ALTER TABLE的五种用法(四、五)

首发微信公众号&#xff1a;SQL数据库运维 原文链接&#xff1a;https://mp.weixin.qq.com/s?__bizMzI1NTQyNzg3MQ&mid2247485212&idx1&sn450e9e94fa709b5eeff0de371c62072b&chksmea37536cdd40da7a94e165ce4b4c6e70fb1360d51bed4b3566eee438b587fa231315d0a5a…

MySQL数据库复习——事务

目录 一、什么是事务&#xff1f;为什么需要事务 二、事务的四大特性&#xff08;ACID&#xff09; 三、事务的使用 四、并发带来的问题 1、脏读问题 2、不可重复读 3、幻读 五、MySQL的隔离级别 一、什么是事务&#xff1f;为什么需要事务 事务的概念&#xff1a; 事务…

深度解析Linux内核—中断

中断 中断是外围设备通知处理器的一种机制。 1. 中断控制器 外围设备不是把中断请求直接发送给处理器&#xff0c;而是发给中断控制器&#xff0c;由中断控制器转发给处理器。 不同种类的中断控制器的访问方法存在差异&#xff0c;为了屏蔽差异&#xff0c;内核定义了中断控…

model.eval 至关重要!!!!model.eval()是否开启 BN 和 Dropout 的不同

之前写过一个项目&#xff0c;eval的时候很正常&#xff0c;但是一infer就有问题&#xff0c;多次排查发现&#xff0c;原来就是只缺一个 model.eval()哇&#xff0c;重大教训&#xff0c;我debug好久&#xff0c;在小姑娘面前翻车… &#x1f923;&#x1f923;&#x1f923;…

样本与抽样分布(2)-基本分布

本节介绍在数理统计中常用的几个基本分布。为此&#xff0c;先引进分位数定义。 定义1. 2. 1 设X为随机变量&#xff0c;则称满足 的为X的上侧分位数,简称为(上侧)分位数. 1 标准正态分布 标准正态分布N (0,1)是构造其他分布的基础&#xff0c;其密度函数为 它的图形关于y轴…

【毕业设计】深度学习卫星遥感图像检测与识别系统(目标检测)

文章目录0 前言1 课题背景2 实现效果3 Yolov5算法4 数据处理和训练5 最后0 前言 &#x1f525; Hi&#xff0c;大家好&#xff0c;这里是丹成学长的毕设系列文章&#xff01; &#x1f525; 对毕设有任何疑问都可以问学长哦! 这两年开始&#xff0c;各个学校对毕设的要求越来…

LeetCode-44-通配符匹配

1、递归 具体思路同LeetCode-剑指19-正则表达式匹配&#xff0c;但在本题中由于字符串长度过长会导致超时。 在这里插入代码片class Solution { public:bool isMatch(string s, string p) {if (p.empty()) return s.empty();bool first_match !s.empty() && (s[0] …

Gradle修改镜像库 ,初始启动配置 init.gradle

目录 ■前言 ■代码放置位置 ■具体代码 代码建议&#xff1a; ■Gradle 的 更多知识&#xff08;私密&#xff09; ■前言 默认镜像库太慢了&#xff0c;在【初始启动配置&#xff08;init.d&#xff09;】中&#xff0c;添加xxx.gradle (init.gradle) 文件&#xff0c;指…

网络自动化运维(NetDevOps)创作者推荐

前言&#xff1a; 随着NetDevOps技术登上了历史舞台&#xff0c;越来越多的从业者开始利用NetDevOps简化网络的运维&#xff0c;并进行了技术分享&#xff0c;将蛋糕越做越大。在这里&#xff0c;仅代表个人对这些无私奉献的网络、运维工程师们表达由衷的敬意。 此外&#xff…

用户身份验证的令牌—Token教程

一、什么是Token&#xff1f; 1、Token的引入&#xff1a;Token是在客户端频繁向服务端请求数据&#xff0c;服务端频繁的去数据库查询用户名和密码并进行对比&#xff0c;判断用户名和密码正确与否&#xff0c;并作出相应提示&#xff0c;在这样的背景下&#xff0c;Token便应…

学习二十大奋进新征程线上知识答题小程序登录技术点分析与实现

学习二十大奋进新征程线上知识答题小程序登录技术点分析与实现 在最新搭建的知识答题小程序&#xff0c;遇到了微信授权登录上的技术难点&#xff0c;所以对于以往的那套登录框架不能使用了&#xff0c;需要搭建一套新的注册登录流程框架。 不得不做出调整&#xff0c;为此&a…

json交叉编译并移植到嵌入式开发板

1、解压&#xff1a;tar -xvf json-c-0.9.tar.gz 默认解压在当前目录 2、进入解压后的目录&#xff1a;$ cd cd json-c-0.9/ 3、执行&#xff1a; sudo ./configure CCaarch64-linux-gnu-gcc --hostarm-linux --prefix/opt/json-c-0.9/ 说明&#xff1a;CC赋值为嵌入式开发环…