给定一个由不同正整数的组成的非空数组 A,考虑下面的图:
有 A.length 个节点,按从 A[0] 到 A[A.length - 1] 标记;
只有当 A[i] 和 A[j] 共用一个大于 1 的公因数时,A[i] 和 A[j] 之间才有一条边。
返回图中最大连通组件的大小。
输入:[4,6,15,35]
输出:4
总结一下题目的意思,若a和b有一个大于1的公因数,则a和b属于1组,假如a和b一组,b和c一组,那么a和c也是一组。
很显然是一个并查集的题目,这题的关键是确定任意两个数是否属于一组,确定之后就是一个并查集的裸题了。
判断任意两个数是否有大于1的公因数,最好想的暴力是两次遍历数组,对于每个不同的a,b,用一次gcd(a,b)求最大公因数,这样时间复杂度是O(n^2logn),这道题的n是20000,显然超时。
另一个比较好想的办法是枚举质因数,题目规定数组中的每个数都不大于100000,使用质数筛可以枚举小于100000的所有质数,大约有10000个,然后作为公因数去枚举这些质因数,这样时间复杂度变成了O(10000*n),还是超时。
再接着考虑到*如果m = p1p2…pn(n>1),m是数组中的数,那么min(p1,p2,…,pn)不会超过sqrt(100000)≈350,原因很显然如果最小的p比350要大,那么p*p就已经大于题目中规定的最大值100000了,显然不符合题意。
考虑到任意两个数的质因数要么不大于350,要么大于350,所以我们先考虑公因数不大于350的情况,这种情况很好解决,将小于350的质数作为公因数枚举一下数组中所有的数字就能解决,如果遇到了两个数有共同的因数则用并查集合并一下即可。
到目前为止都比较好想到,而下一步卡了我很久,就是如果两个数唯一的质因数大于350怎么办,我们不可能枚举所有不大于100000的质因数,这会超时,但如果不去枚举所有的质因数,我们就没办法判断两个数是否属于一个集合。
!!!!!!!!!!!!!!!!!!!!!!!!!
每个数不小于350的质因数最多只有一个,这个刚才已经说过了,所以我们如果把一个数小于350的质因数全部排除,那么最后剩下的就是这个大于350的质因数。
排除不大于350的质因数可以在刚才的遍历中解决,如果某个质数是数组中某个数的质因数,那么就用数组中的数一直除以这个质数,这样遍历完所有的质数,数组中剩下的数只有两种可能,要么是1,要么是一个大于350的质数,用一个occur[100000]标记数组中是否存在某个质因数,如果当前数为n,之前occur[n]!=0,说明之前有一位和当前位拥有一个相同的大于350的质因数,再合并即可。
class Solution {
public:
int not_prime[405];
int prime[405];
int father[20005];
int sum[20005];
int occur[100005];
int find(int x)
{
if(father[x]==x)
return x;
int fx = find(father[x]);
father[x] = fx;
return fx;
}
int largestComponentSize(vector<int>& A) {
not_prime[1] = 1;
for(int i=2;i<=400;i++)
{
if(not_prime[i]==1)
continue;
for(int j=i+i;j<=400;j+=i)
not_prime[j] = 1;
}
int cnt = 0;
for(int i=1;i<=400;i++)
{
if(not_prime[i]==0)
prime[++cnt] = i;
}
int ans = 1;
int size = A.size();
for(int i=0;i<size;i++)
{
father[i] = i;
sum[i] = 1;
}
for(int i=1;i<=cnt;i++)
{
int pre = -1;
for(int j=0;j<size;j++)
{
if(A[j]%prime[i]==0)
{
if(pre==-1)
pre = j;
else
{
int fx = find(pre);
int fy = find(j);
if(fx!=fy)
{
father[fx] = fy;
sum[fy]+=sum[fx];
ans = max(ans,sum[fy]);
}
pre = j;
}
while(A[j]%prime[i]==0)
A[j]/=prime[i];
}
}
}
for(int i=0;i<size;i++)
{
if(A[i]==1)
continue;
if(occur[A[i]]==0)
{
occur[A[i]] = i+1;
continue;
}
else
{
int fx = find(occur[A[i]] - 1);
int fy = find(i);
if(fx!=fy)
{
father[fx] = fy;
sum[fy]+=sum[fx];
ans = max(ans,sum[fy]);
}
occur[A[i]] = i+1;
}
}
return ans;
}
};