LeetCode/按公因数计算最大组件大小(并查集)

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

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

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

1. 并查集(从后往前)

//每个数从后往前按公因数建冗余集合,根据公因数合并集合,根节点为当前数
class Solution {
public:
    vector<int> parent;
    int largestComponentSize(vector<int>& nums) {
        // 根据最大值确定集合上限
        int maxNum = INT_MIN;
        for (int num : nums)
            maxNum = max(maxNum, num);
        // 最大的范围是 maxNum + 1, 而不是maxNum,要考虑0的情况
        parent.resize(maxNum+1);
        for (int i = 0; i < parent.size(); ++i)
            parent[i] = i;//每个数为一个集合

        // 一簇公因数建立一个集合,公因数存在相同则集合合并
        for (int num : nums)
            for (int i = sqrt(num); i >= 2; --i)//从后往前
                if (num % i == 0) // 取可以被整除的情况,即可连通
                {
                    unions(num, i);//大的并小的,本质上也是根据公因数去并另一个集合
                    unions(num, num / i);
                }

        // 再次遍历去计数
        unordered_map<int, int> cnt;
        for (int num : nums)
            ++cnt[find(num)];

        int res = 0;
        for (auto iter = cnt.begin(); iter != cnt.end(); ++iter)
            res = max(res, iter->second);

        return res;
    }

    int find(int x){//路径压缩
        if (parent[x] == x) return x;
        parent[x] = find(parent[x]);
        return parent[x];
    }

    void unions(int x, int y){
        x = find(x);
        y = find(y);
        if(x==y) return;
        parent[y] = x;
    }

};

从前往后
// 从前往后,主动去找在同一集合的元素,根节点为公因数
vector<bool> prime(maxNum+1,1);
unordered_set<int> s(nums.begin(),nums.end());
for (int i = 2; i <= maxNum; i++)//遍历所有公因数
    if (prime[i]) {//减少重复查找
        for (int j = i * 2; j <= maxNum; j += i) {
            prime[j] = 0;
            if (s.count(j)) parent[find(j)] = find(i);//合并集合(根节点)
        }
    }

2. 暴力建图(深度优先)

class Solution {
public:
    int largestComponentSize(vector<int>& nums) {
        vector<vector<int>>  graph(nums.size());
        //建立邻接表图
        for(int i=0;i<nums.size();i++)
            for(int j=i+1;j<nums.size();j++){
                if(gcd(nums[i],nums[j])>1){
                    graph[i].push_back(j);
                    graph[j].push_back(i);
                }
            }
        vector<bool> visit(nums.size());
        int res = INT_MIN;
        for(int i=0;i<nums.size();i++){
            int count = 0;
            dfs(i,graph,visit,count);
            res = max(count,res);
        }
        return res;  
    }
    void dfs(int i,vector<vector<int>>&graph,vector<bool>&visit,int&count){
        if(visit[i]) return;
        visit[i] = 1;
        count++;
        for(int j=0;j<graph[i].size();j++)
            dfs(graph[i][j],graph,visit,count);
    }
};
posted @ 2022-07-30 15:19  失控D大白兔  阅读(90)  评论(0编辑  收藏  举报