常见的并查集题目

在这里插入图片描述

总结

并查集逻辑实现的优化有两种,第一种是查找时路径压缩,第二种是按秩合并,合并时将高度较小的树作为较高树的子树,从代码量来看,推荐使用路径压缩,可以参考lc 547. 省份数量的两种UnionFind写法

题目

1 LC990. 等式方程的可满足性

class Solution {class UnionFind{int[]p;int[]rank;public UnionFind(int n){p=new int[n];rank=new int[n];for(int i=0;i<n;i++){p[i]=i;rank[i]=1;}}public void union(int x,int y){int r1=find(x);int r2=find(y);if(r1==r2)return;if(rank[r1]>rank[r2]){p[r2]=r1;}else if(rank[r1]<rank[r2]){p[r1]=r2;}else{p[r2]=r1;rank[r1]++;}}public int find(int x){while(x!=p[x]){x=p[x];}return x;}}public boolean equationsPossible(String[] equations) {int n=equations.length;UnionFind uf=new UnionFind(26);for(int i=0;i<n;i++){String equation=equations[i];int a=equation.charAt(0)-'a';int b=equation.charAt(3)-'a';if(equation.charAt(1)=='=')uf.union(a,b);}for(int i=0;i<n;i++){String equation=equations[i];int a=equation.charAt(0)-'a';int b=equation.charAt(3)-'a';if(equation.charAt(1)=='!'){if(uf.find(a)==uf.find(b)){return false;}}}return true;}
}

2 lc 547. 省份数量

class Solution {boolean[]vis;public int findCircleNum(int[][] isConnected) {int n = isConnected.length;vis=new boolean[n];int ans=0;for(int i=0;i<n;i++){if(!vis[i]){bfs(isConnected,i,n);ans++;}}return ans;}public void bfs(int[][] c,int i,int n){Deque<Integer>q=new ArrayDeque<>();q.offerLast(i);while(!q.isEmpty()){int size=q.size();for(int j=0;j<size;j++){int cno=q.pollFirst();if(vis[cno])continue;vis[cno]=true;for(int k=0;k<n;k++){if(c[cno][k]==1){q.offerLast(k);}}}}}public void dfs(int[][] c,int i,int n){if(i<0||i>=n){return;}if(vis[i])return;vis[i]=true;for(int j=0;j<n;j++){if(c[i][j]==1){dfs(c,j,n);}}}// 当合并时,比较两个树的rank,将rank(也指高度)值大的树的根作为合并后的根节点。class UnionFind{int[]p;int[]rank;public int cnt;public UnionFind(int n){cnt=n;p=new int[n];rank=new int[n];for(int i=0;i<n;i++){p[i]=i;rank[i]=1;}}public void union(int x,int y){int r1=find(x);int r2=find(y);if(r1==r2)return;cnt--;if(rank[r1]>rank[r2]){p[r2]=r1;}else if(rank[r1]<rank[r2]){p[r1]=r2;}else{p[r2]=r1;rank[r1]++;}}public int find(int x){while(x!=p[x]){x=p[x];}return x;}}public int findCircleNum2(int[][] isConnected) {int n = isConnected.length;UnionFind uf = new UnionFind(n);for( int i = 0; i < n; ++i ) {for( int j = 0; j < n; ++j ) {if(i!=j&&isConnected[i][j]==1){uf.union(i,j);}}}return uf.cnt;}
}
// 路径压缩版的并查集数据结构class UnionFind2{int[]p;int[]rank;public int cnt;public UnionFind2(int n){cnt=n;p=new int[n];rank=new int[n];for(int i=0;i<n;i++){p[i]=i;rank[i]=1;}}public void union(int x,int y){int r1=find(x);int r2=find(y);if(r1==r2)return;cnt--;p[r2]=r1;rank[r1]++;}public int find(int x){while(x!=p[x]){x=p[x];}return x;}}

3 1319. 连通网络的操作次数

复杂的思路:还要分别计算每个连通子图内的

class Solution {List<List<Integer>> list;boolean[] visited;int[]w;public int makeConnected2(int n, int[][] connections) {if (connections.length < n - 1) {return -1;}list=new ArrayList<>();visited=new boolean[n];w=new int[n];for(int i=0;i<n;i++){list.add(new ArrayList<>());} int len=connections.length;for(int i=0;i<len;i++){int x=connections[i][0];int y=connections[i][1];list.get(x).add(y);list.get(y).add(x);}int need=-1;for(int i=0;i<n;i++){if(!visited[i]){dfs2(list,i);need++;}}return need;}public void dfs2(List<List<Integer>> list,int id){if(visited[id])return;visited[id]=true;for(int i=0;i<list.get(id).size();i++){dfs2(list,list.get(id).get(i));}}public int makeConnected(int n, int[][] connections) {if (connections.length < n - 1) {return -1;}UnionFind uf=new UnionFind(n);for(int i=0;i<connections.length;i++){int x=connections[i][0];int y=connections[i][1];uf.union(x,y);}int r=0;int cnt=0;for(int i=0;i<n;i++){if(uf.p[i]==i){cnt++;}}    return cnt-1;}class UnionFind{int[]p;public UnionFind(int n){p=new int[n];for(int i=0;i<n;i++){p[i]=i;}}public int find(int x){if(p[x]!=x){p[x]=find(p[x]);}return p[x];}public void union(int x,int y){int r1=find(x);int r2=find(y);if(r1==r2){return;}p[r1]=r2;}}}

4 684. 冗余连接

class Solution {public int[] findRedundantConnection(int[][] edges) {UnionFind uf = new UnionFind( edges.length );int[] res = new int[2];for(int i=0;i<edges.length;i++){int[]e=edges[i];if(uf.find(e[0])==uf.find(e[1]))return new int[]{e[0],e[1]};uf.union(e[0],e[1]);}return res;}class UnionFind{int[]p;public UnionFind(int n){p=new int[n+1];for(int i=1;i<=n;i++){p[i]=i;}}public int find(int x){if(p[x]!=x){p[x]=find(p[x]);}return p[x];}public void union(int x,int y){int r1=find(x);int r2=find(y);if(r1==r2){return;}p[r1]=r2;}}
}

5 1361. 验证二叉树

class Solution {// 并查集用的集合列表List<Integer> p = new ArrayList<>();// 用于统计不相交的连通分支个数int cnt;public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) {// 用于标记各个孩子的父节点int[] father = new int[n];// 初始化Arrays.fill(father, -1);// 初始化并查集集合状态for(int i = 0; i < n; i++) p.add(i);// 初始化分支数cnt = n;// 遍历所有节点for(int i = 0; i < n; i++) {// 如果节点存在两个孩子,而且两个孩子相同,那么显然是错误的二叉树if(leftChild[i] == rightChild[i] && leftChild[i] != -1) return false;// 合并两个孩子if(!merge(father, i, leftChild[i]) || !merge(father, i, rightChild[i])) return false;}// 如果最后所有的节点组成一个连通分支,才是一棵树if(cnt == 1) return true;return false;}// 和并父亲和孩子节点,并判断逻辑private boolean merge(int[] father, int f, int c) {// 孩子是空的,直接返回if(c == -1) return true;// 孩子之前有爸爸了,就是错的if(father[c] != -1) return false;// 并查集查找两个集合的根int a = find(f), b = find(c);// 如果孩子和父亲已经存在于一个集合中,那么说明会产生环,返回错误if(a == b) return false;// 合并两个集合p.set(a, b);// 标记孩子的父亲是谁father[c] = f;// 连通分支数减一cnt --;return true;}// 并查集通用方法,找集合的根元素private int find(int x) {if(p.get(x) != x) {p.set(x, find(p.get(x)));}return p.get(x);}
}作者:lippon
链接:https://leetcode.cn/problems/validate-binary-tree-nodes/solutions/663937/java-bing-cha-ji-yi-ci-bian-li-xiang-xi-6450j/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
根据上面这个方法自己写的一个并查集版本:
class Solution {public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) {UnionFind uf=new UnionFind(n);for(int i=0;i<n;i++){if(leftChild[i]!=-1&&!uf.union(leftChild[i],i)){return false;}if(rightChild[i]!=-1&&!uf.union(rightChild[i],i)){return false;}}return uf.cnt==1;}public class UnionFind{int[]p;int cnt;public UnionFind(int n){p=new int[n];for(int i=0;i<n;i++){p[i]=i;}cnt=n;}public int find(int x){//路径压缩if(p[x]!=x){p[x]=find(p[x]);}return p[x];}public boolean union(int x,int y){int rx=find(x);int ry=find(y);if(rx==ry)return false;//如果之前就已经在一个连通图中,则合并失败if(p[x]!=x)return false;//如果之前已经有爸爸了,则也合并失败p[rx]=ry;cnt--;return true;}}}

6 LC399. 除法求值

class Solution {public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {int n=values.length;HashMap<String, Integer>mp=new HashMap<>();UnionFind uf=new UnionFind(2*n);int k=0;for(int i=0;i<n;i++){String a=equations.get(i).get(0);String b=equations.get(i).get(1);if(!mp.containsKey(a))mp.put(a,k++);if(!mp.containsKey(b))mp.put(b,k++);uf.union(mp.get(a),mp.get(b), values[i]);}int m=queries.size();double[] ans=new double[m];for(int i=0;i<m;i++){String a=queries.get(i).get(0);String b=queries.get(i).get(1);int aa=mp.getOrDefault(a,-1);int bb=mp.getOrDefault(b,-1);if(aa==-1||bb==-1){ans[i]=-1.00;continue;}// bfs搜索ans[i]=uf.compute(aa,bb);}return ans;}class UnionFind{double[]w;int[]p;public UnionFind(int n){w=new double[n];p=new int[n];for(int i=0;i<n;i++){w[i]=1.0d;p[i]=i;}}public int find2(int x){while(p[x]!=x){int pn=p[x];p[x]=p[p[x]];w[x]=w[x]*w[pn];x=p[x];}return p[x];}public int find(int x) {if(x!=p[x]){int pn=p[x];p[x]=find(p[x]);w[x]*=w[pn];}return p[x];}public void union(int x,int y, double val){int rx=find(x);int ry=find(y);if(rx==ry)return;p[rx]=ry;w[rx]=w[y]*val/w[x];}public double compute(int x, int y){int rx=find(x);int ry=find(y);if(rx!=ry){return -1.0d;}return w[x]/w[y];}}public double[] calcEquation2(List<List<String>> equations, double[] values, List<List<String>> queries) {int n=values.length;HashMap<String, Integer>mp=new HashMap<>();double[][]mat=new double[2*n][2*n];int k=0;for(int i=0;i<n;i++){String a=equations.get(i).get(0);String b=equations.get(i).get(1);if(!mp.containsKey(a))mp.put(a,k++);if(!mp.containsKey(b))mp.put(b,k++);mat[mp.get(a)][mp.get(b)]=values[i];mat[mp.get(b)][mp.get(a)]=1.0/values[i];}int m=queries.size();double[] ans=new double[m];for(int i=0;i<m;i++){String a=queries.get(i).get(0);String b=queries.get(i).get(1);int aa=mp.getOrDefault(a,-1);int bb=mp.getOrDefault(b,-1);if(aa==-1||bb==-1){ans[i]=-1.00;continue;}// bfs搜索ans[i]=bfs(mat,aa,bb);}return ans;}double bfs(double[][]mat,int a, int b){int n=mat.length;Deque<double[]>q=new LinkedList<>();q.offerLast(new double[]{a*1.00,1.00});boolean[]vis=new boolean[n];while(!q.isEmpty()){int size=q.size();for(int i=0;i<size;i++){double poll[]=q.pollFirst();if(poll[0]==(double)b){return poll[1];}double[]neighbors=mat[(int)poll[0]];for(int j=0;j<neighbors.length;j++){if(!vis[j]&&(double)neighbors[j]!=(double)0.00){vis[j]=true;q.offerLast(new double[]{j, poll[1]*mat[(int)poll[0]][j]});}}}}return -1.00;}
}

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

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

相关文章

一文讲透Linux应用编程—进程原理

文章目录 程序的开始和结束main函数由谁调用&#xff1f;程序是如何结束的&#xff1f;atexit注册进程终止处理函数return、 exit、_exit三者区别 进程环境环境变量进程运行的虚拟空间 进程的正式引入什么是进程&#xff1f;进程ID多进程调度原理 fork创建子进程为什么要创建子…

教你用python画图—Turtle详细教程

Turtle模块绝对是吸引非专业代码开发者人员学习python入门的好工具 通过turtle几行代码的执行软件就会画出漂亮的图形&#xff0c;美观而且有成就感&#xff0c;这样一下子对python编程就产生了兴趣。 这些漂亮的图形如三角形、五角星、机器猫等。在写代码的时候改变几个参数…

BLE Mesh蓝牙组网技术详细解析之Foundation Model Layer基础模型层(七)

目录 一、什么是BLE Mesh Foundation Model Layer基础模型层&#xff1f; 二、模型 2.1 配置模型 2.2 健康模型 三、状态 3.1 Composition Data 四、资料获取 一、什么是BLE Mesh Foundation Model Layer基础模型层&#xff1f; BLE Mesh Foundation model Layer是蓝牙…

拼多多砍价群2024年最新二维码

随着移动互联网的快速发展&#xff0c;小程序成为了人们生活中不可或缺的一部分。它们轻便、快捷&#xff0c;无需下载安装&#xff0c;即可随时随地使用。在这个背景下&#xff0c;小程序互助群应运而生&#xff0c;成为了一种新型的社群形式&#xff0c;旨在帮助用户更好地利…

基于sy3130光感入耳检测功能成功实现

基于sy3130光感入耳检测功能成功实现 是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务,+群赠送语音信号处理降噪算法,蓝牙耳机音频,DSP音频项目核心开发资料, 1 芯片介绍 2 电路实现 3 寄存器列表

Linux习题1

解析&#xff1a;Tcsh是csh的增强版&#xff0c;并且完全兼容csh。它不但具有csh的全部功能&#xff0c;还具有命令行编辑、拼写校正、可编程字符集、历史记录、作业控制等功能。 AWK是一种优良的文本处理工具&#xff0c;Linux及Unix环境中现有的功能最强大的数据处理引擎之一…

60.网游逆向分析与插件开发-游戏增加自动化助手接口-游戏公告功能的逆向分析与测试

内容来源于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;文字资源读取类的C还原-CSDN博客 码云地址&#xff08;master分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/sro_-ex.git 码云版本号&#xff1a;878db7708de09b448010ef54526fe…

新手深入浅出理解PyTorch归一化层全解析

目录 torch.nn子模块normal层详解 nn.BatchNorm1d BatchNorm1d 函数简介 函数工作原理 参数详解 使用技巧与注意事项 示例代码 nn.BatchNorm2d BatchNorm2d 函数简介 函数工作原理 参数详解 使用技巧与注意事项 示例代码 nn.BatchNorm3d BatchNorm3d 函数简介 参…

Linux文件的扩展属性 attr cap

文件属性 Linux文件属性分为常规属性与扩展属性&#xff0c;其中扩展属性有两种&#xff1a;attr与xattr. 一般常规的文件属性由stat API 读取&#xff0c;一般是三种权限&#xff0c;ower, group&#xff0c;时间等。 扩展属性attr 用户态API ioctl(fd, FS_IOC32_SETFLAGS…

Windows中磁盘未知没有初始化怎么办?

当我们尝试在Windows11/10/8/7上使用外部硬盘驱动器时&#xff0c;在小概率情况下可能会遇到磁盘未知没有初始化情况&#xff0c;此时如果您进入磁盘管理工具中查看&#xff0c;将会发现您的外部硬盘驱动器显示为未知、未初始化、没有磁盘空间&#xff0c;或者在某些情况下它还…

二进制安装包安装Prometheus插件安装(mysql_exporter)

简介 mysql_exporter是用来收集MysQL或者Mariadb数据库相关指标的&#xff0c;mysql_exporter需要连接到数据库并有相关权限。既可以用二进制安装部署&#xff0c;也可以通过容器形式部署&#xff0c;但为了数据收集的准确性&#xff0c;推荐二进制安装。 一&#xff0c;下载安…

批量AI智剪方法:轻松学会视频剪辑,让你的视频更精彩

在数字媒体时代&#xff0c;视频剪辑已经成为一项重要的技能。对于许多初学者来说&#xff0c;视频剪辑可能是一项复杂且耗时的任务。那么如何解决这个问题呢&#xff1f;现在一起来看看云炫AI智剪如何批量剪辑的方法&#xff0c;轻松完成视频剪辑工作&#xff0c;让视频更加精…