码迷,mamicode.com
首页 > 其他好文 > 详细

并查集

时间:2020-03-16 23:47:39      阅读:87      评论:0      收藏:0      [点我收藏+]

标签:comm   父节点   输出   就是   计组   路径压缩   组件   扁平化   mon   

一、场景


 

并查集多数是用来解决连通性问题的

如至少修建几条路可以使所有路口可以相通

把互通的路口当做一个群组,那问题就是有几个这样的群组

如有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] 之间才有一条边。
返回图中最大连通组件的大小。
 
示例 1:
输入:[4,6,15,35]
输出:4
示例 2:
输入:[20,50,9,63]
输出: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;
    }

}

 

 

 


 

并查集

标签:comm   父节点   输出   就是   计组   路径压缩   组件   扁平化   mon   

原文地址:https://www.cnblogs.com/yangfei629/p/12507587.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!