1. 程式人生 > >leetcode 952. 按公因數計算最大元件大小 (素數篩法+並查集)

leetcode 952. 按公因數計算最大元件大小 (素數篩法+並查集)

題意:

給一串數,每一個數代表圖的一個節點,然後兩個數之間有除1之外的公因數表示這兩個節點之間有邊相連,求最大連通圖。

做法:

如果平方找數兩兩之間是否存在公因數肯定超時,如果要判斷兩個數是否有公因數,只需要判斷有沒有含有相同的素數就可以了。

那麼我們可以對每一個數進行一個歸類,含有2的數,含有3的數,含有5的數,含有7的數。。。等等

對於都含有公因子2的數,那麼肯定都相連。對於含有3的數,肯定也都相連。那麼2和3這個群體相不相連呢?就得看有沒有公共元素,所以這其實是一個很基礎的並查集的模型。

怎麼樣合併呢?如果有a,b兩個元素,那麼我們只需要定義這兩個元素的最終父親是兩個父親間最小的那一個就ok。

程式碼:

class Solution {
public:
int all_num = 100000;
int prime[100005];
int fa[100005];
void get_prime(){//得到所有的素數
    memset(prime,0,sizeof(prime));
    vector<int>ans;
    int len = 0;
    for(int i=2;i<=all_num;i++){
        if(!prime[i])ans.push_back(i),len++;
        for(int j=0;j<len&&ans[j]*i<=all_num;j++){
            prime[ans[j]*i] = 1;
            if(i%ans[j]==0)break;
        }
    }
}

int get_father(int x){//路徑壓縮得到父親
    while(fa[x]!=x){
        int f = fa[x];
        fa[x] = fa[f];
        x = f;
    }
    return x;
}

void init(){
    for(int i=0;i<=all_num;i++)fa[i] = i;
}

int largestComponentSize(vector<int>& A) {
    get_prime();
    init();
    int sz = A.size();
    for(int i=0;i<sz;i++){
        for(int d = 2;d*d<=A[i];d++){#如果遍歷所有的素數會超時,因為素數有一萬個。所以只能用根號的時間複雜度來遍歷
            if(A[i]%d==0&&!prime[d]){
                int fa1 = get_father(A[i]);
                int fa2 = get_father(d);
                fa[fa1] = fa[fa2] = min(fa1,fa2);
            }
            if(A[i]%d==0&&!prime[A[i]%d]){
                int fa1 = get_father(A[i]);
                int fa2 = get_father(A[i]/d);
                fa[fa1] = fa[fa2] = min(fa1,fa2);
            }
        }
    }
    map<int,int>ma; //最後用一個map來找到最終最大的集團,因為這個集團所有人的父親都是同一個。
    int mma = 0;
    for(int i=0;i<sz;i++){
        int fa1 = get_father(A[i]);
        ma[fa1] = ma[fa1] + 1;
        if(ma[fa1]>mma)mma = ma[fa1];
    }
    return mma;
}
};