b_lc_数组的最大公因数排序(并查集+质因数分解优化)
一个整数数组 nums ,你可以在 nums 上执行下述操作 任意次 :
- 如果 gcd(nums[i], nums[j]) > 1 ,交换 nums[i] 和 nums[j] 的位置。其中 gcd(nums[i], nums[j]) 是 nums[i] 和 nums[j] 的最大公因数。
如果能使用上述交换方式将 nums 按 非递减顺序 排列,返回 true ;否则,返回 false 。
思路:如果两层循环判断是否可以和另一个数交换,然后加入到并查集的话会超时,这里用质因数分解进行优化,直接将每个数的公因子加到并查集
class Solution {
public:
struct UF {
int* fa;
int* sz;
UF(int N) {
fa = new int[N + 5];
sz = new int[N + 5];
for (int i = 1; i <= N; i++) {
fa[i] = i, sz[i] = 1;
}
}
int find(int u) {
return fa[u] == u ? u : fa[u] = find(fa[u]);
}
void merge(int u, int v) {
int fu = find(u), fv = find(v);
if (sz[fu] > sz[fv]) {
fa[fv] = fu;
// sz[fu] += sz[fv];
} else {
fa[fu] = fv;
// sz[fv] += sz[fu];
}
}
bool isConn(int u, int v) {
return find(u) == find(v);
}
};
bool gcdSort(vector<int>& A) {
int n = A.size();
UF* uf = new UF(3e5 + 5);
vector<int> B = A;
sort(B.begin(), B.end());
for (int x : A) {
int t = x;
for (int i = 2; i <= t / i; ++i) {
bool find = false;
while (t % i == 0) {
t /= i;
find = true;
}
if (find) {
uf->merge(x, i);
}
}
if (t > 1) {
uf->merge(x, t);
}
}
for (int i = 0; i < n; ++i) {
if (A[i] != B[i]) {
if (!uf->isConn(A[i], B[i])) {
return false;
}
}
}
return true;
}
};