1998. 数组的最大公因数排序
思路:并查集。
1、可以交换的两个位置,一定是在同一个"最大公因数>1"的集合。即:a和b的最大公约数>1,b和c的最大公约数>1。那么a、b、c都是可以交换的。
2、如果两层循环来判断数组里的任意两个的最大公约数是否>1,那么时间复杂度0(n^2),超时了。这里可以对每个nums[i]进行质因数分解,然后将它和它的所有质因数都用并查集合并到一个集合。时间复杂度0(n*sqrt(n))。
3、解决了是否可以交换的问题,接着就是看数组交换后能否按“非递减顺序”排列。这里直接用新的数组nums1来复制一份数组nums,将nums进行排序,接着和nums1进行对比。相同的值直接继续,不同就看是否在一个集合里,不在就返回false。
细节看注释
class Solution {
const int N=1e5+10;
public:
int p[100010];
int findd(int u){
if(p[u]!=u) p[u]=findd(p[u]);
return p[u];
}
void merge(int a,int b){
int ta=findd(a),tb=findd(b);
if(ta!=tb) p[ta]=tb;
}
bool gcdSort(vector<int>& nums) {
//并查集
for(int i=0;i<N;i++){
p[i]=i;
}
//对每个nums[i]进行质因数分解
for(int i=0;i<nums.size();i++){
int t=nums[i];
//将它和它的所有质因数都用并查集合并到一个集合
for(int j=2;j<=t/j;j++){
bool flag=0;
while(t%j==0){
t/=j;
flag=1;
}
if(flag){
merge(nums[i],j);
}
}
if(t>1){
merge(nums[i],t);
}
}
//用新的数组nums1来复制一份数组nums
vector<int> nums1=nums;
//将nums进行排序
sort(nums.begin(),nums.end());
bool flag=1;
//接着和nums1进行对比
for(int i=0;i<nums.size();i++){
//相同的值直接继续,不同就看是否在一个集合里
if(nums[i]!=nums1[i]){
//不在就返回false
if(findd(nums[i])!=findd(nums1[i])){
flag=0;
break;
}
}
}
return flag;
}
};