952. 按公因数计算最大组件大小

难度困难

给定一个由不同正整数的组成的非空数组 nums ,考虑下面的图:

  • nums.length 个节点,按从 nums[0]nums[nums.length - 1] 标记;
  • 只有当 nums[i]nums[j] 共用一个大于 1 的公因数时, nums[i]nums[j] 之间才有一条边。

返回 图中最大连通组件的大小

示例 1:

img

输入:nums = [4,6,15,35]

输出:4

示例 2:

img

输入:nums = [20,50,9,63]

输出:2

示例 3:

img

输入:nums = [2,3,6,7,4,12,21,39]

输出:8

提示:

  • 1 <= nums.length <= 2 * 10^4
  • 1 <= nums[i] <= 10^5
  • nums 中所有值都 不同

# 分解质因数 + 并查集

每个数看作一个点,那么只有二者的 gcd>1gcd > 1 时,才会有边。

若直接每两个元素建图,那么时间复杂度为 n2n^2 级别。

我们可以用质因数作为中间点,让元素与其所有的质因数构成边。最后检查连通分量的最大值即可

img

由于每个数最多有 lognlog\,n 个质因数,即最终的时间复杂度为 O(nlog(nA))O(n\,log(n\cdot A)),其中 AA 为并查集的操作复杂度

class Solution {
    public int largestComponentSize(int[] nums) {
        // 分解质因数 + 并查集
        // 以质因数作为转折点
        init(200002);
        int n = nums.length;
        for (int j = 0; j < n; j++) {
            int num = nums[j];
            // 分解质因数
            for (int i = 2; i * i <= num; i++) {
                boolean f = false;
                while (num % i == 0) {
                    f = true;
                    num /= i;
                }
                // 合并 j, i
                if (f) {
                    union(j, n + i);
                }
            }
            // 若 num > 1,那么此时 num 也是一个质因数
            if (num > 1) {
                union(j, n + num);
            }
        }
        // 检查连通分量
        int ans = 0;
        int[] cnt = new int[n];
        for (int i = 0; i < n; i++) {
            ans = Math.max(ans, ++cnt[find(i)]);
        }
        return ans;
    }
    int[] father;
    public void init(int n) {
        father = new int[n];
        for (int i = 1; i < n; i++) {
            father[i] = i;
        }
    }
    public void union(int i, int j) {
        int lAncestor = find(i);
        int rAncestor = find(j);
        // 让质因数的父节点指向原数
        // 这样在分组的时候使得父节点不会超过 n
        // - cnt[find(i)]++;
        father[rAncestor] = lAncestor;
    }
    public int find(int x) {
        if (x == father[x]) {
            return x;
        }
        return father[x] = find(father[x]);
    }
}