数组的最大公因数排序(分解质因子+并查集)
题目描述
给你一个整数数组 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; } };