并查集
Posted yangfei629
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并查集相关的知识,希望对你有一定的参考价值。
一、场景
并查集多数是用来解决连通性问题的
如至少修建几条路可以使所有路口可以相通
把互通的路口当做一个群组,那问题就是有几个这样的群组
如有N个群组 那至少修N-1条路 就可以把所有路口相连。
二、使用
并查集分两步
1、合并
合并就是把相连的多个节点划到一个群组中
可以定义数组parent[] 表示对应节点的父节点索引。
这样不断查询节点A的父节点,可以找到组先节点(父节点就是本身的节点)
所谓相连节点就是设置同一个组先节点
2、查询
查询两个节点是否相连,只要判断各自的组先节点是否相同,如果相同,就是相连的
在查询的过程中 可以路径压缩(节点的父节点直接指向组先节点),使结构扁平化,提升查询效率
三、示例
如leecode第952题:按公因数计算最大组件大小
给定一个由不同正整数的组成的非空数组 A,考虑下面的图:
有 A.length 个节点,按从 A[0] 到 A[A.length - 1] 标记;
只有当 A[i] 和 A[j] 共用一个大于 1 的公因数时,A[i] 和 A[j] 之间才有一条边。
返回图中最大连通组件的大小。
只有当 A[i] 和 A[j] 共用一个大于 1 的公因数时,A[i] 和 A[j] 之间才有一条边。
返回图中最大连通组件的大小。
示例 1:
输入:[4,6,15,35]
输出:4
输出:4
示例 2:
输入:[20,50,9,63]
输出:2
输出:2
这个问题就是一个并查集的问题,只要知道哪些数是一组的,再求出最大一组的元素个数即可
解题如下
class Solution { private class UnionFindUtil { // 对应父节点位置 private int[] parent; // 初始化 每个元素的父节点索引==自身索引 public UnionFindUtil(int n) { parent = new int[n]; for (int i = 0; i < n; i++) { parent[i] = i; } } // 查找 public int find(int x) { if (parent[x] == x) { return x; } // 路径压缩 parent[x] = find(parent[x]); return parent[x]; } // 合并 public void union(int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX != rootY) { parent[rootX] = rootY; } } } public int largestComponentSize(int[] A) { int maxVal = 0; for (int num : A) { maxVal = Math.max(maxVal, num); } // 使用质数来判断是否两连 UnionFindUtil unionFind = new UnionFindUtil(maxVal + 1); for (int num : A) { double upBound = Math.sqrt(num); for (int i = 2; i <= upBound; i++) { if (num % i == 0) { unionFind.union(num, i); unionFind.union(num, num / i); } } } // 找出最大者 int[] cnt = new int[maxVal + 1]; int res = 0; for (int num : A) { int root = UnionFindUtil.find(num); // 统计组先节点出现的次数 每次加一 cnt[root]++; res = Math.max(res, cnt[root]); } return res; } }
以上是关于并查集的主要内容,如果未能解决你的问题,请参考以下文章