数组的最大公因数排序(分解质因子+并查集)

题目描述

给你一个整数数组 nums ,你可以在 nums 上执行下述操作 任意次 :

如果 gcd(nums[i], nums[j]) > 1 ,交换 nums[i] 和 nums[j] 的位置。其中 gcd(nums[i], nums[j]) 是 nums[i] 和 nums[j] 的最大公因数。
如果能使用上述交换方式将 nums 按 非递减顺序 排列,返回 true ;否则,返回 false 。

 

输入:nums = [7,21,3]
输出:true
解释:可以执行下述操作完成对 [7,21,3] 的排序:
- 交换 7 和 21 因为 gcd(7,21) = 7 。nums = [21,7,3]
- 交换 21 和 3 因为 gcd(21,3) = 3 。nums = [3,7,21]

输入:nums = [10,5,9,3,15]
输出:true
解释:
可以执行下述操作完成对 [10,5,9,3,15] 的排序:
- 交换 10 和 15 因为 gcd(10,15) = 5 。nums = [15,5,9,3,10]
- 交换 15 和 3 因为 gcd(15,3) = 3 。nums = [3,5,9,15,10]
- 交换 10 和 15 因为 gcd(10,15) = 5 。nums = [3,5,9,10,15]

题目解析

题意为任意两个数的公因数大于1,那么这两个数可以交换。由此可知如果a和b可交换,b和c可交换,那么a,b,c三者可以任意改变顺序,不难想到用并查集把所有公因数大于1的两个数合并

以后凡是看到a->b,b->c====>a->c,就用并查集

 记得之前在矩阵中好像也又一道这样的题,就是一行中能换,然后找联通块

 

 

 

Code

const int maxn=1e6+100;
int pre[maxn];
class Solution {
public:
    int find(int x){
        if(pre[x]==x){
            return pre[x];
        }
        return pre[x]=find(pre[x]);
    }
    void marge(int x,int y){
        int fx=find(x);
        int fy=find(y);
        if(fx==fy){
            return ;
        }
        pre[fx]=fy;
    }
    bool gcdSort(vector<int>& nums) {
        int n=nums.size();
        for(int i=0;i<maxn;i++){
            pre[i]=i;
        }
        for(auto x:nums){
            int z=x;
            for(int i=2;i*i<=x;i++){
                if(x%i==0){
                    marge(i,z);
                }
                while(x%i==0){
                    x/=i;
                }
            }
            if(x>1){
                marge(x,z);
            }
        }
        vector<int> sorted_nums(nums);
        sort(sorted_nums.begin(), sorted_nums.end());
        for (int i = 0; i < n; i++){
            if (find(nums[i]) != find(sorted_nums[i])){
                return false;
            }
        }
        return true;
    }
};

 

posted @ 2021-09-15 17:01  lipu123  阅读(171)  评论(0)    收藏  举报