基础算法合集-并查集

<蓝桥杯软件赛>零基础备赛20周--第17周--并查集 并查集 阅读详情

1.概念

并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。 并查集的思想是用一个数组表示了整片森林(parent),树的根节点唯一标识了一个集合,我们只要找到了某个元素的的树根,就能确定它在哪个集合里

2.如何实现

我推荐听这个视频(老师是边写代码,边画图), 讲起来很通俗, 画的图也很直观。 如果后续刷题的时候忘了就再看一遍,几分钟的视频也不会花费你很多时间。

进阶数据结构和算法-249-图-并查集-2_哔哩哔哩_bilibili

3.代码实现

核心代码部分

class DisjointSet{
    int[] s;
    public DisjointSet(int size){
        s=new int[size];
        for(int i=0;i<size;i++){
            s[i]=i;
        }
        public int find(int x){
            if(x==s[x]){
                return x;
            }
            return find(x);
        }
        public void union(int x,int y){
            s[y]=x;
        }
    }
}
public class Main {
	public static void main(String[] args) {
	    DisjointSet set=new DisjointSet(7);	
	}
}

下面我们通过一道题来帮助你入门并查集

题目描述

给定一个列表 accounts,每个元素 accounts[i] 是一个字符串列表,其中第一个元素 accounts[i][0] 是 名称 (name) ,其余元素是 emails 表示该账户的邮箱地址。 现在,我们想合并这些账户。如果两个账户都有一些共同的邮箱地址,则两个账户必定属于同一个人。请注意,即使两个账户具有相同的名称,它们也可能属于不同的人,因为人们可能具有相同的名称。一个人最初可以拥有任意数量的账户,但其所有账户都具有相同的名称。 合并账户后,按以下格式返回账户:每个账户的第一个元素是名称,其余元素是 按字符 ASCII 顺序排列 的邮箱地址。账户本身可以以 任意顺序 返回。

原题链接:  721. 账户合并 - 力扣(LeetCode)

 账户合并-代码实现(C++)

class DisjointSet{
public:
    vector<int> parent;
    DisjointSet(int n){
        parent.resize(n);
        for(int i=0;i<n;i++){
            parent[i]=i;
        }
    }
    int find(int x){
        if(parent[x]!=x){
            return find(parent[x]);
        }
        return parent[x];
    }
    void Union(int x,int y){
        parent[find(y)]=find(x);
    }
};
class Solution {
public:
    vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {
        int m=accounts.size();
        unordered_map<string,int> mp;
        DisjointSet uf(m);
        for(int i=0;i<m;i++){
            int n=accounts[i].size();
            for(int j=1;j<n;j++){
                string email=accounts[i][j];
                if(mp.count(email)==0){
                    mp[email]=i;
                }else{
                    uf.Union(i,mp[email]);
                }
            }
        }
        map<int,vector<string>> ms;
        for(auto& [email,idx]:mp){
            int fa=uf.find(idx);
            ms[fa].push_back(email);
        }
        vector<vector<string>> ans;
        for(auto& [idx,email]: ms){
            vector<string> userAccount;
            userAccount.push_back(accounts[idx][0]);
            vector<string> sortedEmail=email;
            sort(sortedEmail.begin(),sortedEmail.end());
            userAccount.insert(userAccount.end(),sortedEmail.begin(),sortedEmail.end());
            ans.push_back(userAccount);
        }
        return ans;
    }
};
/*
[["John", "johnsmith@mail.com", "john00@mail.com"], 
["John", "johnnybravo@mail.com"], 
["John", "johnsmith@mail.com", "john_newyork@mail.com"], 
["Mary", "mary@mail.com"]]

[["John", 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'],  
["John", "johnnybravo@mail.com"],
["Mary", "mary@mail.com"]]
只要邮箱地址有相同的就能进行合并, 结果按任意顺序返回
*/

 账户合并-代码实现(Java)

class UnionFind {
    int[] parent;

    public UnionFind(int n) {
        parent = new int[n];
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
    }

    public void union(int index1, int index2) {
        parent[find(index2)] = find(index1);
    }

    public int find(int index) {
        if (parent[index] != index) {
            parent[index] = find(parent[index]);
        }
        return parent[index];
    }
}
class Solution {
    public List<List<String>> accountsMerge(List<List<String>> accounts) {
       int m=accounts.size();
       Map<String,Integer> hm1=new HashMap<>(); 
       UnionFind uf=new UnionFind(m);
       for(int i=0;i<m;i++){
          List<String> account=accounts.get(i);
          int n=account.size();
          for(int j=1;j<n;j++){
            String email=account.get(j);
            if(!hm1.containsKey(email)){
                hm1.put(email,i);
            }else{
                uf.union(i,hm1.get(email));
            }
          }
       }
       Map<Integer,List<String>> hm2=new TreeMap<>();
       for(Map.Entry<String,Integer> e: hm1.entrySet()){
         String email = e.getKey();
         int idx=e.getValue();
         int fa=uf.find(idx);
         if(!hm2.containsKey(fa)){
            hm2.put(fa,new ArrayList<String>());
         }
         hm2.get(fa).add(email);
       }
       List<List<String>> ans=new ArrayList<>();
       for(Map.Entry<Integer,List<String>> e:hm2.entrySet()){
          int idx=e.getKey();
          List<String> x=e.getValue();
          Collections.sort(x);
          List<String> tmp=new ArrayList<>();
          tmp.add(accounts.get(idx).get(0));
          tmp.addAll(x);
          ans.add(tmp);
       }
       return ans;
    }
}

实现思路

解题思路的话,其实就是按题目模拟就行, 在阅读代码的时候, 可能会有的疑问我来解释一下

unordered_map<string,int> mp;

它用来记录:

每个 邮箱地址 (email) 对应的账户索引 (index)。

换句话说:

当我们在遍历每个账户的邮箱时,

  • 如果某个邮箱第一次出现,就把它存进哈希表,并记录这个邮箱来自哪个账户(用 i 表示账户下标)。
  • 如果某个邮箱已经在哈希表里出现过了,说明当前账户和之前的那个账户是同一个人的(因为有相同邮箱),所以就用并查集合并它们。(合并账户)

举个例子帮助理解:

假如输入是:

accounts = [
  ["John", "a@mail.com", "b@mail.com"],
  ["Mary", "c@mail.com"],
  ["John", "b@mail.com", "d@mail.com"]
]

步骤

遍历到的账户

邮箱

emailToIndex 记录

并查集操作

1账户0 ("John")a@mail.coma@mail.com -> 0无
2账户0 ("John")b@mail.comb@mail.com -> 0无    
3账户1 ("Mary")c@mail.comc@mail.com -> 1无
4账户2 ("John")b@mail.com已存在 -> 0合并账户2和账户0
5账户2 ("John")d@mail.comd@mail.com -> 2无

作用总结一句话:

mp 用于快速判断邮箱是否出现过,并帮助找到它第一次出现的账户,从而用并查集把这些账户合并在一起,归属到同一个人。

map<int,vector> ms;
这个 map<int, vector<string>> ms 主要用于在合并完账户后,按照每个合并后的用户收集他们的所有邮箱地址

作用:

它用来记录:

每个并查集的根节点(也就是合并后的“代表账户”的索引)对应的所有邮箱列表

为什么要用它?

因为同一个人可能有多个账户,这些账户通过相同的邮箱地址被并查集合并在了一起。
最后我们需要知道每个合并后的人的所有邮箱地址。
这时候:

ms 的 key 是并查集的根节点索引(代表这个人的账户索引)。
value 是这个人的所有邮箱地址的集合。

结合例子来看:

比如这个例子:

accounts = [
  ["John", "a@mail.com", "b@mail.com"],
  ["Mary", "c@mail.com"],
  ["John", "b@mail.com", "d@mail.com"]
]

经过并查集合并后:

  • 账户 0 和 账户 2 是同一个人(因为都有 "b@mail.com")。
  • 账户 1 是 Mary。

那么 indexToEmails 大概是:

{
  0: ["a@mail.com", "b@mail.com", "d@mail.com"],  // John
  1: ["c@mail.com"]                               // Mary
}
vector<vector> ans; (往ans里面填充答案即可)

如何将vector<string> b, 追加到vector<string> a的结尾呢, 这里推荐使用insert这个成员函数
insert方法可以将一个容器的内容插入到另一个容器的指定位置。如果你想将`cnt`追加到`ans`的末尾,可以这样写:
    ans.insert(ans.end(), cnt.begin(), cnt.end());
    这里的ans.end()表示插入的位置是ans的末尾,cnt.begin()和cnt.end()分别表示要插入的内容的范围

 

ACM算法模板 · 一些常用的算法模板-模板合集(打比赛专用) 萌新常用的都在这了,本萌新的模板集。 阅读详情

相关推荐

并查集(边带权,拓展域)

ACM-ICPC模板 路径压缩和按秩合并 int fa[N]; void init(){ for(int i = 1;i <= n;++i) fa[i] = i; memset(Rank,0, sizeof Rank); } int getfa(int x){//查询 if(fa[x] == x) return x; return fa[x] = getfa(fa[x]); } inline void union( int x, int y){/

繁凡さん的博客 2818

普林斯顿大学_算法公开课:Part_1_第一部分:并查集

首先,给大家推荐一个平台,Coursera (类比国内的mooc网),你可以在上面学习诸多国外一流大学的公开课视频,各个领域的都有,涉猎范围很广。想要出国留学的小伙伴儿不妨在上面事先感受一波国外授课的氛围与模式。言归正传,作为一名程序猿,算法实在是太重要了!即便不是一名程序员,学习一下算法编程也是很有好处的。因为,在某种层面上讲,算法是你针对计算机进行的解决问题的思想上的映射,代码就是你想法的载体...

GZHarryAnonymous的博客 1986

算法学习021 c++有多少张桌子 并查集算法学习 中小学算法思维学习 比赛算法题解 信奥算法解析

C++有多少张桌子 一、题目要求 1、编程实现 今天是小明的生日。他邀请了很多朋友。现在是晚餐时间。小明想知道他至少需要多少张桌子。你必须注意到,不是所有的朋友都互相认识,而并不是所有的朋友都想和陌生人呆在一起。 这个问题的一个重要规则是,如果我告诉你 A 认识 B,B 认识 C,那就意味着 A、B、C 互相认识,所以他们可以呆在一张桌子上。不考虑一张桌子能做多少人,问需要多少张桌子。 例如:如果我告诉你 A 认识 B,B 认识 C,D 认识 E,所以 A、B、C 可以呆在一张桌子上,而 D、E 必须

青少年编程学习指导 1259

并查集(入门讲解)

并查集 所谓并查集,类似于找朋友 现在有一群人(总共n个人),两两之间组成了朋友。 而且朋友的朋友也是自己的朋友(比如A和B是朋友,A和C也是朋友,那么A,B,C他们三个就互为朋友。) 而由于我们给数据时只会给K个数,代表这K个人是朋友(一般K的值是2) 并查集作用 1.用来看某个人A和另一个人B是不是朋友, 2.用于查看n个人中,组成了几个朋友圈(两个朋友圈就代表,这两组人互不认识)。 3.有时...

qq_41268947的博客 865

Linux与Windows双系统,安装完linux后无法通过grub进入Windows的解决方法

先装Windows 10,Windows可正常启动,再装Kali,Kali提示装grub后照装。然而装完后重启发现无Windows选项。

sakurashockwave的博客 6453

LLVM 编译器学习笔记之三十六-- 指令调度Instruction scheduling

1、参考Instruction scheduling in LLVM - 知乎,在中后端均存在指令调度 指令调度模型 2、在llvm12->llvm14 中Machine Instruction Scheduler有个patch增强了load/store指令的合并,也就是指令调度不仅仅只是改变指令的顺序,该优化类似gcc中的store-merge优化 .....................................................................

~ 飞 扬 的 天 空 ~ 5685

超有爱的并查集~

例子就是杭电上的畅通工程: http://acm.hdu.edu.cn/showproblem.php?pid=1232 首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题。比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块。像畅通工程这题,问还需要修几条路,实质...

peizhiinfo 1334

红外弱小目标检测:IPI算法解读及MATLAB复现

参考文献:[1]C. Gaoet al., “Infrared Patch-Image Model for Small Target Detection in a Single Image,” vol. 22, no. 12, pp. 4996–5009, 2013. 本文整理????论文笔记,并附MATLAB实现代码。 一、阅读笔记 1. 摘要 IPI算法是单帧检测算法; 利用背景的非局部子相关性(non-local self-correlation ofbackground),将目标检测转..

小草莓的魔法笔记 1万+

Canopy:面向生产的RAG框架实战指南

RAG(检索增强生成)是当前大模型落地的核心范式,其工程化难点集中于文本分块、向量索引一致性、多轮对话上下文管理及生产级可观测性。Canopy 作为专为生产环境设计的RAG框架,通过语义分块、模块化解耦(KB/CE/ChE)、Pinecone Serverless原生集成与OpenAI API兼容接口,显著降低RAG服务从开发到上线的综合成本。它不替代对embedding原理或LLM机制的理解,而是将重复性‘脏活’标准化——如自动chunking、命名空间隔离、Prometheus指标暴露与优雅关闭支持,让

weixin_33676492的博客 414

3D Gaussian Splatting环境配置和运行

使用conda命令根据environment.yml文件创建虚拟环境时,安装的pytorch是使用conda install 命令来安装的,实际上并不能成功安装带有gpu的pytorch,而这两个模块的安装依赖于带gpu的pytorch。如果不注释掉这三行,直接安装会报错

m0_46360757的博客 3326

华为OD机考双机位C卷 - 天然蓄水库(Java & Python& JS & C/C++ & GO )

华为OD机考双机位C卷 - 天然蓄水库(OD上机考试双机位C卷)。提供在线OJ刷题。Java、C++、Python、GO语言、C语言、JavaScript题解,并提供完整思路讲解。

算法大师! 1740

并查集详解

并查集是我暑假从高手那里学到的一招,觉得真是太精妙的设计了。以前我无法解决的一类问题竟然可以用如此简单高效的方法搞定。不分享出来真是对不起party了。(party:我靠,关我嘛事啊?我跟你很熟么?) 来看一个实例,杭电1232畅通工程 http://acm.hdu.edu.cn/showproblem.php?pid=1232 首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你...

lianxiangbus 1万+

【推荐100个unity插件之2】 DoTween动画插件的安装和使用整合(最全)

摘要:DOTween动画插件使用指南 DOTween是Unity中强大的动画插件,比原生动画更便捷。安装后需进行初始化设置,通过工具菜单生成程序集。主要提供通用方法(DOTween.To)和便捷方法(如transform.DOMove)两种动画实现方式。插件支持丰富的动画设置(循环、缓动等)和事件回调(OnComplete、OnKill)。还提供动画管理功能,包括清除(DOTween.Clear)、完成(DOTween.CompleteAll)和终止(DOTween.KillAll)动画。常用功能涵盖移动、

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 1万+

并查集练习题合集

世界上 比金钱个更可贵的是知识,比知识更可贵的是,好奇心。 加油! 并查集练习题合集一、基础用法回归二、简单并查集 一、基础用法回归 并查集 : 合并两个集合 或者查询一个元素是否在集合中 题目: 二、简单并查集 三、 ...

惟愿一生无悔也无憾 2411

华为OD机试真题 C 实现【水库蓄水问题】【2022.11 Q4 新题】

给定一个长度为 n 的整数数组height。数组的元素表示山的高度,选择两个元素作为水库的边界,求蓄水量的最大值并输出蓄水量最大时的边界下标(蓄水量相同时输出下标较近的)。

MISAYAONE的博客 1万+

摆脱英文束缚!群晖Transmission4.0.4全新中文界面攻略

在群晖安装完官方Transmission4.0.4套件后,界面是英文状态的,不太好用。但是按照网上分享的原来4.0以前版本的方法更新UI又失败,所以自己搞了下成功了,分享给需要的朋友。

XiaoqiangClub的博客 5208

算法基础 - 并查集

用于解决动态连通性问题,能动态连接两个点,并且判断两个点是否连通。方法描述UF(int N)构造一个大小为 N 的并查集连接 p 和 q 节点查找 p 所在的连通分量编号判断 p 和 q 节点是否连通i < N;😁热门专栏推荐想学习vue的可以看看这个java基础合集数据库合集redis合集nginx合集linux合集手写机制微服务组件spring_尘觉springMVCmybits🤔欢迎大家加入我的社区尘觉社区。

业精于勤,荒于嬉 745

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

并查集详解+例题合集

擒贼先擒王——解密犯罪团伙: 没错,就是他们,为了下层劳动阶级的利益开始扰乱朝廷治安了。 虽然他们是一家人,但是这些好汉们分成了许多队伍分开出动,我们需要做的是确定他们分成了多少个队伍。 我们先来了解一下并查集: 并查集,并查集是一种树形结构,又叫“不相交集合”,保持了一组不相交的动态集合,每个集合通过一个代表来识别,代表即集合中的某个成员,通常选择根做这个代表。 并查集,并查集是一种树形结构,...

Bearing in mind forever! 750

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

力扣并查集题目合集

并查集基础:并查集被很多OIer认为是最简洁而优雅的数据结构之一,主要用于解决一些的问题。它管理一系列。

weixin_43757333的博客 478

算法笔记练习 题解合集

说明 带链接的小节标题是该链接对应的 codeup 地址 第 3 章 入门篇(1)——入门模拟 3.6 字符串处理 问题 A: 字符串连接 问题 B: 首字母大写 问题 C: 字符串的查找删除 问题 D: 单词替换 问题 E: 字符串去特定字符 问题 F: 数组逆置 问题 G: 比较字符串 问题 H: 编排字符串 问题 I: 【字符串】回文串 第 4 章 入门篇(2)——算法初步 4.1 ...

Gorgeoustray 4444

ACM算法合集

数据结构: 栈、堆、队列、链表 散列,开散列、闭散列 集合、位集合 优先队列 并查集、带权的并查集 映射二叉堆 树堆 Treap 基本算法: 贪心算法 分治算法 二分求等比数列之和 LCA与RMQ问题 大数 DFS和BFS A* 和IDA* 直接插入排序、折半插入排序、希尔排序 冒泡排序、快速排序 选择排序、堆排序 二路归并排序 桶排序 区间查询算法: 线段树 莫队、树上莫队 树链剖分 主席树 树状数组 串: KMP、扩展KMP manacher回文字符串 Trie Tree AC自动机 后缀

1815

并查集 合集

poj 1182 我觉得应该算是基础。 不过这道题 discuss 提出的那种向量方法,觉得很受局限。不过想出此种方法的我膜拜之。此大牛也。其实我觉得这道题应该是按三个并查集或者两个来做是正解。 因为如果题目食物链不是三个 ,而是4个,甚至一百个。这个方法才能解。而上面那种方法太特殊。poj 1988  题意: M a b, 代表含b的链要并到含a的链条的后面。  C代表 输出a 后面有多少个元素。不知不觉就a了,我还以为会wa ,做法和 《算法艺术》那本书的 81页 ,银河英雄传说查不多。 三个 数组

mindmb的专栏 1005

算法与数据结构--并查集

序 两个点是否连接, 在大型网络中,肉眼很难观察出来。 如何判断一个巨大网络中两个点是否连接,这个网络不一定是互联网,也可能是微信中的人际关系网,两个人是否是好友,是否有连接?巨大数据库中,电影与音乐是否有交集, 网络路由器是否连接?他们的连接路径有多少条?具体路径分别是什么? 想要解决两个点是否连接,是否有交集的问题,最快速的方法就是使用并查集。 而要解决他们的连接路径有多少以及具体路径,就需...

追yi流年 340

并查集题目合集

一、畅通工程 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1232#include&lt;bits/stdc++.h&gt; using namespace std; int bin[1010]; int findx(int x){ int r=x; while(bin[r]!=r){ r=bin[r]; } return r; } v...

XXXX的博客 4530

【算法题归纳合集】高级数据结构-并查集

一、AcWing 1250. 格子游戏 【题目描述】 Alice和Bob玩了一个古老的游戏:首先画一个n×nn×nn×n的点阵(下图n=3n=3n=3)。 接着,他们两个轮流在相邻的点之间画上红边和蓝边: 直到围成一个封闭的圈(面积不必为111)为止,“封圈”的那个人就是赢家。因为棋盘实在是太大了,他们的游戏实在是太长了! 他们甚至在游戏中都不知道谁赢得了游戏。 于是请你写一个程序,帮助他们计算他们是否结束了游戏? 【输入格式】 输入数据第一行为两个整数nnn和mmm。nnn表示点阵的大小,mmm表示一共

一只快乐的小蒟蒻~ 631

算法合集——并查集union-find

并查集算法主要分为quic-find, quick-union以及union-find方法。但出于效率考虑,一般使用union-find算法进行实际操作。         union-find算法的思想就是利用一个数组id[]记录每个节点的父节点,例如现要将节点1(id[1] = 1)连接到节点2(id[2] = 2),则令id[1] = 2即可;同时,若节点为根节点,则令其id值等于其自身。通

qq_35599454的博客 454
上一篇: 基础算法合集-二分查找(三种写法)
下一篇: 基础算法合集-线段树
一只鱼^_
博客等级 码龄3年 1073粉丝 92原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值