并查集

本文用于个人算法竞赛学习,仅供参考

目录

一.什么是并查集

二.并查集实现

三.路径优化

四.时间复杂度

五.并查集+路径压缩 模板

五.题目


一.什么是并查集

并查集(Disjoint Set)是一种数据结构,用于处理一系列不相交的集合的合并与查询问题。并查集主要支持两种操作:

1. 合并(Union):将两个集合合并为一个集合。
2. 查询(Find):确定一个元素属于哪个集合,通常用于判断两个元素是否属于同一个集合。

并查集通常使用树结构来表示集合,其中每个节点表示一个元素,树的根节点表示集合的代表元素。通过路径压缩和按秩合并(没什么用)等优化方式,可以在近似常数时间内进行合并和查询操作。

二.并查集实现

1.存储方式

使用一维数组来实现,通过数组将元素连通在一起,就相当于将元素放在同一个集合中了。比如将A、B、C放在同一个集合,有

2.功能实现

const int N = 10010;
int father[N];//并查集寻根的过程--递归
int find(int u)
{//等于本身就是根节点,返回根节点if (u == father[u])return u;//不是根节点,向下寻根elsereturn find(father[u]);
}// v -> u加入这条边
void join(int u, int v)
{u = find(u);//寻根v = find(v);//寻根//同一集合就不用加入了if (u == v)return;father[v] = u;
}//判断是否同一个集合---是否同一个根
bool isSame(int u, int v)
{u = find(u);//寻根v = find(v);//寻根return u == v;
}//初始化---每个节点初始化指向自己
void init()
{for (int i = 0; i < N; i++){father[i] = i;}
}

三.路径优化

对于一个集合,将其抽象成树形结构可能是:

 对于find函数,其实是一个寻根过程,比如

对于插入一条边和查询是否同一个集合,都是通过查找根节点后进行操作的,那么find的效率就取决于路径的长度,既然都是找根,那么同一个集合的元素直接插到同一个节点不就行了,将树的结构改成:

这样每次find就不用递归那么多层了,这种思想就是路径压缩。

只需要改一下find函数就可以实现:
 

int find(int u) {return u == father[u] ? u : father[u] = find(father[u]);
}

四.时间复杂度

路径压缩后的并查集时间复杂度在O(logn)与O(1)之间,且随着查询或者合并操作的增加,时间复杂度会越来越趋于O(1)。 

五.并查集+路径压缩 模板

const int N = 10010;
int father[N];//并查集寻根的过程--递归
int find(int u)
{return u == father[u] ? u : father[u] = find(father[u]);
}// v -> u加入这条边
void join(int u, int v)
{u = find(u);//寻根v = find(v);//寻根//同一集合就不用加入了if (u == v)return;father[v] = u;
}//判断是否同一个集合---是否同一个根
bool isSame(int u, int v)
{u = find(u);//寻根v = find(v);//寻根return u == v;
}//初始化---每个节点初始化指向自己
void init()
{for (int i = 0; i < N; i++){father[i] = i;}
}

五.题目

 1971. 寻找图中是否存在路径 - 力扣(LeetCode)

class Solution {//并查集//模板实现
private:int n = 200005;vector<int> father = vector<int>(n, 0);//初始化void init(){for(int i = 0; i < n; i++){father[i] = i;}   }//find找根,路径压缩实现int find(int u){return u == father[u] ? u : father[u] = find(father[u]);}//判断是否同根bool isSame(int u, int v){u = find(u);v = find(v);return u == v;}//加入同一集合 v -> uvoid join(int u, int v){u = find(u);v = find(v);if(u == v){return;}father[v] = u;}public:bool validPath(int n, vector<vector<int>>& edges, int source, int destination) {init();for(int i = 0; i < edges.size(); i++){join(edges[i][0], edges[i][1]);}return isSame(source,destination);}
};

 684. 冗余连接 - 力扣(LeetCode)

class Solution {//并查集
private:int n = 1005;vector<int> father = vector<int>(n, 0);//初始化void init(){for(int i = 0; i < n; i++){father[i] = i;}}//查找&&并查集int find(int u){return father[u] == u ? u : father[u] = find(father[u]);}//判断是否同一跟根节点bool isSame(int u, int v){u = find(u);v = find(v);return u == v;}//加入同一集合void join(int u, int v){u = find(u);v = find(v);if(u == v){return;}father[v] = u;}
public:vector<int> findRedundantConnection(vector<vector<int>>& edges) {init();//记得初始化for(int i = 0; i < n; i++){if(isSame(edges[i][0], edges[i][1]))return edges[i];elsejoin(edges[i][0], edges[i][1]);}return {};}
};

 685. 冗余连接 II - 力扣(LeetCode)

class Solution {
private:static const int N = 1010; // 如题:二维数组大小的在3到1000范围内int father[N];int n; // 边的数量// 并查集初始化void init() {for (int i = 1; i <= n; ++i) {father[i] = i;}}// 并查集里寻根的过程int find(int u) {return u == father[u] ? u : father[u] = find(father[u]);}// 将v->u 这条边加入并查集void join(int u, int v) {u = find(u);v = find(v);if (u == v) return ;father[v] = u;}// 判断 u 和 v是否找到同一个根bool same(int u, int v) {u = find(u);v = find(v);return u == v;}// 在有向图里找到删除的那条边,使其变成树vector<int> getRemoveEdge(const vector<vector<int>>& edges) {init(); // 初始化并查集for (int i = 0; i < n; i++) { // 遍历所有的边if (same(edges[i][0], edges[i][1])) { // 构成有向环了,就是要删除的边return edges[i];}join(edges[i][0], edges[i][1]);}return {};}// 删一条边之后判断是不是树bool isTreeAfterRemoveEdge(const vector<vector<int>>& edges, int deleteEdge) {init(); // 初始化并查集for (int i = 0; i < n; i++) {if (i == deleteEdge) continue;if (same(edges[i][0], edges[i][1])) { // 构成有向环了,一定不是树return false;}join(edges[i][0], edges[i][1]);}return true;}
public:vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {int inDegree[N] = {0}; // 记录节点入度n = edges.size(); // 边的数量for (int i = 0; i < n; i++) {inDegree[edges[i][1]]++; // 统计入度}vector<int> vec; // 记录入度为2的边(如果有的话就两条边)// 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案for (int i = n - 1; i >= 0; i--) {if (inDegree[edges[i][1]] == 2) {vec.push_back(i);}}// 处理图中情况1 和 情况2// 如果有入度为2的节点,那么一定是两条边里删一个,看删哪个可以构成树if (vec.size() > 0) {if (isTreeAfterRemoveEdge(edges, vec[0])) {return edges[vec[0]];} else {return edges[vec[1]];}}// 处理图中情况3// 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了return getRemoveEdge(edges);}
};

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

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

相关文章

一文了解JAVA的常用API

目录 常用kpimathSystemRuntimeObjectObjectsBigIntegerBigDecima正则表达式包装类 常用kpi 学习目的&#xff1a; 了解类名和类的作用养成查阅api文档的习惯 math 工具类。因为是工具类&#xff0c;因此直接通过类名.方法名(形参)即可直接调用 abs&#xff1a;获取参数绝对…

Linux学习:进程(4)程序地址空间(笔记)

目录 1. Linux下各种资源的内存分布2. 物理地址与虚拟(线性)地址3. 程序地址空间的区域划分4. 地址映射与页表5. 缺页中断 1. Linux下各种资源的内存分布 2. 物理地址与虚拟(线性)地址 在有关进程创建的初步学习中&#xff0c;我们了解了fork函数创建子进程的方式。此种进程的创…

Spring Boot 一.基础和项目搭建(上)

之前也自学过SSM框架&#xff0c;Spring Boot框架&#xff0c;也动手写过几个项目&#xff0c;但是这是第一次完整的记录。从0开始&#xff0c;把一些细节整理了一下。 大概会分为十几小节&#xff0c;这是一个学习的过程&#xff0c;更是一个思考的过程&#xff0c;废话不多说…

金融汽车科技LLM

汇丰银行 众安保险 1. AIGC重塑保险价值链 小额高频 2.构建智能应用的技术方案演进 增加微服务 长记忆&#xff1a;向量库短记忆&#xff1a;对话历史&#xff0c;思考路径&#xff0c;执行历史 中台架构设计 蔚来汽车在大模型的应用实践 公司介绍 应用架构 应用实践 4.大…

Django框架之DRF(武沛齐全)

一、FBV和CBV FBV&#xff0c;function base views&#xff0c;其实就是编写函数来处理业务请求。 from django.contrib import admin from django.urls import path from app01 import views urlpatterns [path(users/, views.users), ] from django.http import JsonResp…

快速排序---算法

1、算法概念 快速排序&#xff1a;通过一趟排序将待排记录分隔成独立的两部分&#xff0c;其中一部分记录的数据均比另一部分的数据小&#xff0c;则可分别对这两部分记录继续进行排序&#xff0c;以达到震哥哥序列有序。 快速排序的最坏运行情况是O()&#xff0c;比如说顺序数…

网络基础二补充——json与http协议

五、市面上常用序列化和反序列化工具 ​ 常用的有&#xff1a;json、protobuf、xml三种方案&#xff1b; 5.1json的使用 1.安装jsoncpp库&#xff0c;是一个第三方的开发库文件&#xff1b; sudo yum install -y jsoncpp-devel2.使用json ​ 经常使用的头文件是json.h&…

【uC/OS-III篇】uC/OS-III 创建第一个任务(For STM32)

uC/OS-III 创建第一个任务&#xff08;For STM32&#xff09; 日期&#xff1a;2024-3-30 23:55&#xff0c;结尾总结了今天学习的一些小收获 本博客对应的项目源码工程 源码项目工程 1. 首先定义错误码变量 // 用于使用uC/OS函数时返回错误码 OS_ERR err; 2. 定义任务控制…

Golang | Leetcode Golang题解之第2题两数相加

题目&#xff1a; 题解&#xff1a; func addTwoNumbers(l1, l2 *ListNode) (head *ListNode) {var tail *ListNodecarry : 0for l1 ! nil || l2 ! nil {n1, n2 : 0, 0if l1 ! nil {n1 l1.Vall1 l1.Next}if l2 ! nil {n2 l2.Vall2 l2.Next}sum : n1 n2 carrysum, carry …

Vue ElementPlus Input输入框

Input 输入框 通过鼠标或键盘输入字符 input 为受控组件&#xff0c;它总会显示 Vue 绑定值。 通常情况下&#xff0c;应当处理 input 事件&#xff0c;并更新组件的绑定值&#xff08;或使用v-model&#xff09;。否则&#xff0c;输入框内显示的值将不会改变。不支持 v-mode…

【面试经典150 | 动态规划】最小路径和

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;动态规划方法二&#xff1a;空间优化 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题…

MCGS学习——水位控制

要求 插入一个水罐&#xff0c;液位最大值为37插入一个滑动输入器&#xff0c;用来调节水罐水位&#xff0c;滑动输入器最大调节为液位最大值&#xff0c;并能清楚的显示出液位情况用仪表显示水位变化情况&#xff0c;仪表最大显示设置直观清楚方便读数&#xff0c;主划线为小…

设计模式-结构型-享元模式Flyweight

享元模式的特点&#xff1a; 享元模式可以共享相同的对象&#xff0c;避免创建过多的对象实例&#xff0c;从而节省内存资源 使用场景&#xff1a; 常用于需要创建大量相似的对象的情况 享元接口类 public interface Flyweight { void operate(String extrinsicState); } 享…

如何使用极狐GitLab 自定义 Pages 根域名

本文作者&#xff1a;徐晓伟 GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 本文主要讲述了极狐GitLab Pages …

普发Pfeiffer 真空TCP120-TCP380-TCP035-TCP600 使用手侧

普发Pfeiffer 真空TCP120-TCP380-TCP035-TCP600 使用手侧

C++进阶:多态(笔记)

目录 1. 多态相关概念1.1 简述&#xff1a;多态1.2 概念汇总与补充 2. 多态重写的底层原理2.1 虚函数存储的结构与位置2.2 重写覆盖 1. 多态相关概念 1.1 简述&#xff1a;多态 1. 什么是多态 不同的对象去做同一个行为时&#xff0c;得到的结果不同。反应到编程语言中&#…

Go语言HTTP服务实现GET和POST请求的同时支持

引言 在现代的Web开发中&#xff0c;HTTP服务是构建网络应用程序的基础。而支持GET和POST请求是其中最基本、最常见的功能之一。GET请求用于从服务器获取数据&#xff0c;而POST请求则用于向服务器提交数据。在Go语言中&#xff0c;通过标准库中的net/http包&#xff0c;我们可…

实景三维技术:开启自然资源管理的新篇章

随着科技的不断进步&#xff0c;实景三维技术已经在多个领域得到了广泛的应用。而在自然资源管理领域&#xff0c;实景三维技术更是发挥着越来越重要的作用。本文将介绍实景三维在自然资源管理领域的应用&#xff0c;探讨其带来的优势和变革。一、什么是实景三维技术&#xff1…

开源一款剪贴板跨设备共享工具

shigen坚持更新文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 个人IP&#xff1a;shigen 昨天遇到了一个很棘手的问题&#xff1a;我的手机剪贴板需要同步到另外的两台设…

HarmonyOS实战开发-一次开发,多端部署-音乐专辑

简介 基于自适应和响应式布局&#xff0c;实现一次开发、多端部署音乐专辑页面。 相关概念 一次开发&#xff0c;多端部署&#xff1a;一套代码工程&#xff0c;一次开发上架&#xff0c;多端按需部署。支撑开发者快速高效的开发支持多种终端设备形态的应用&#xff0c;实现对…