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;
    }
};
posted @ 2021-09-06 22:08  童年の波鞋  阅读(49)  评论(0编辑  收藏  举报