952. Largest Component Size by Common Factor
952. Largest Component Size by Common Factor
题目: https://leetcode.com/problems/largest-component-size-by-common-factor/
难度: Hard
题意:
- 给n个数
- 将n个数设定为n个节点,如果两个数之间的最大公约数大于1,则连边
- 求图的最大联通分量的大小
思路:
- n的数据量高达2w,如果两两节点计算最大公约数,复杂度是o(n^2logn)
- 我们可以使用素数筛法来取出需要两两画线的数列,比如:取出被2整除的数,被3整除的数。。。
- 求图的最大联通分量可以用并查集来做
- 过程是这样的
- 枚举所有的素数
- 假设当前枚举的素数是i
- 从n个数中取出所有能被i整除的数
- 假设有m个数,那么第1个数跟第m-1个数都跟第0个数做下合并
- 枚举结束后,求最大的集合的大小
- 素数筛法的复杂度是o(nlogn),这里需要做下优化,如果枚举每个素数都得从n个数寻找能被它整除的数,复杂度还是o(nk),k是素数的个数,但如果我们把n个数映射到1-100000的数组中,就可以套用素数筛法了
解法:
bool isPrime[100100];
bool hasValue[100100];
int p[100100];
int size[100100];
class Solution {
public:
bool inited = false;
void init() {
memset(isPrime, true, sizeof(isPrime));
for (int i = 2;i <= 100000;i++) {
if (!isPrime[i]) {
continue;
}
for (int j = i + i;j <= 100000;j += i) {
isPrime[j] = false;
}
}
}
int find_set(int x) {
vector<int> temp;
while (p[x] != x) {
temp.push_back(x);
x = p[x];
}
for (int i = 0;i < temp.size();i++) {
p[temp[i]] = x;
}
return x;
}
void union_set(int x, int y) {
x = find_set(x);
y = find_set(y);
if (x == y) {
return;
}
p[x] = y;
size[y] += size[x];
}
vector<int> find(int prime) {
vector<int> ret;
for (int i = prime;i <= 100000;i += prime) {
if (hasValue[i]) {
ret.push_back(i);
}
}
return ret;
}
int largestComponentSize(vector<int>& A) {
if (!inited) {
init();
inited = true;
}
memset(hasValue, false, sizeof(hasValue));
for (int i = 0;i < A.size();i++) {
hasValue[A[i]] = true;
}
for (int i = 0;i <= 100000;i++) {
p[i] = i;
size[i] = 1;
}
for (int i = 2;i <= 100000;i++) {
if(isPrime[i]) {
vector<int> temp = find(i);
if (temp.size() == 0){
continue;
}
for (int j = 1;j < temp.size();j++) {
union_set(temp[0], temp[j]);
}
}
}
int ret = 0;
for (int i = 0;i <= 100000;i++) {
if (!hasValue[i]) {
continue;
}
int x = find_set(i);
if (size[x] > ret) {
ret = size[x];
}
}
return ret;
}
};