• 并查集应用


    并查集

    至于并查集的教程,可以参考文章算法学习笔记(1) : 并查集,写的很详细和通俗易懂,本文就不再介绍。下面给出并查集代码:

    class UnionFind{
    private:
        vector parent;
        vector rank;  // 合并两个不同元素的parent参考依据
    public:
        UnionFind(int n){
            parent = vector(n);
            rank = vector(n);
            for(int i = 0; i < n ; i++){
                parent[i] = i;
            }
        }
        void uni(int x, int y){
            int rootx = find(x);
            int rooty = find(y);
            if(rootx != rooty){
                if(rank[rootx] > rank[rooty]){
                    parent[rooty] = rootx;
                }else if(rank[rootx] < rank[rooty]){
                    parent[rootx] = rooty;
                }else{
                    parent[rooty] = rootx;
                    rank[rootx]++;
                }
            }
        }
        int find(int x){
            if(parent[x] != x){
                parent[x] = find(parent[x]);
            }
            return parent[x];
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    题目描述

    给定一个由不同正整数的组成的非空数组 nums ,考虑下面的图:

    • nums.length 个节点,按从 nums[0]nums[nums.length - 1] 标记;
    • 只有当 nums[i]nums[j] 共用一个大于 1 的公因数时,nums[i]nums[j] 之间才有一条边。

    返回 图中最大连通组件的大小 。

    思路解析

    返回图中最大连通组件的大小,换言之,找出图中最大子图的节点数目,可以使用并查集来对其进行求解,对于 nums 中的每一个元素 num ,遍历 [2, n u m \sqrt{num} num ],找出所有符合公因子的值,其作为合并的桥梁,最终将所有满足要求的元素 num 放到同一个集合中去。

    说明
    • 并查集数组大小为数组 nums 中的最大值。
    • 对于范围 [ 2 , n u m ] [2, \sqrt{num}] [2,num ] 内的每个正整数 i i i,如果 i i i n u m num num 的因数,则 n u m num num i i i n u m i \frac{num}{i} inum 都属于同一个组件。
    完整代码
    #include 
    #include 
    #include 
    using namespace std;
    
    class UnionFind{
    private:
        vector parent;
        vector rank;
    public:
        UnionFind(int n){
            parent = vector(n);
            rank = vector(n);
            for(int i = 0; i < n ; i++){
                parent[i] = i;
            }
        }
        void uni(int x, int y){
            int rootx = find(x);
            int rooty = find(y);
            if(rootx != rooty){
                if(rank[rootx] > rank[rooty]){
                    parent[rooty] = rootx;
                }else if(rank[rootx] < rank[rooty]){
                    parent[rootx] = rooty;
                }else{
                    parent[rooty] = rootx;
                    rank[rootx]++;
                }
            }
        }
        int find(int x){
            if(parent[x] != x){
                parent[x] = find(parent[x]);
            }
            return parent[x];
        }
    };
    
    class Solution {
    public:
        int largestComponentSize(vector& nums) {
            int m = *max_element(nums.begin(), nums.end()); // 找到vector的最大元素
            UnionFind uf(m + 1);
            for(int num : nums){
                for(int i = 2; i * i <= num; i++){
                    if( num % i == 0){
                        uf.uni(num, i);
                        uf.uni(num, num / i);
                    }
                }
            }
            vector counts(m + 1);
            int ans = 0;
            for(int num : nums){
                int root = uf.find(num);
                counts[root]++;
                ans = max(ans, counts[root]);
            }
            return ans;
        }
    };
    
    int main(){
        // vector nums = {4, 6, 15, 35};
        // vector nums = {20, 50, 9, 63};
        vector nums = {2, 3, 6, 7, 4, 12, 21, 39};
    
        Solution so;
        int ans = so.largestComponentSize(nums);
        cout<< ans << endl;
    
        system("pause");
        return 0;
    }
    // output: 8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
  • 相关阅读:
    Java基础访问权限控制符
    物联网5种无线传输协议特点大汇总
    C++提高:03 STL- 常用容器_2
    ES6继承和ES5继承的区别
    Code For Better 谷歌开发者之声——Google Play
    使用nvim来代替VSCode,神操作
    【多线程(三)】生产者和消费者模式
    MySQL多表查询面试题一
    云计算环境下安全关键技术研究
    .NET 6 实现滑动验证码(二)、基本数据
  • 原文地址:https://blog.csdn.net/roger_royer/article/details/126068924