# Union Find and Prime Factorization

952. Largest Component Size by Common Factor

Union Find is a natural way to combine different sets with connection into one set. So the basic idea is:

• If two numbers have common factor, union them
• During the union process, maintain a set size as the final answer is asking for the set size.

# Plain solution

`class UF{    public:    vector<int> roots;    vector<int> sizes;    UF(int n){        roots.assign(n, 0); for (int i = 0; i < n; ++i)roots[i] = i;        sizes.assign(n, 1);}    int find_set(int x){        return x == roots[x]? x: roots[x] = find_set(roots[x]);    }    void union_set(int x, int y){        int root_x = find_set(x), root_y = find_set(y);        if (root_x == root_y)return;        sizes[root_x] += sizes[root_y];        roots[root_y] = root_x;    }    int get_set_size(int x){        return sizes[x];    }};class Solution {    public:    int largestComponentSize(vector<int>& nums) {        const int n = nums.size();        UF uf(n);        unordered_map<int, vector<int>> graph;        for (int i = 0; i < n; ++i){            int num = nums[i];            for (int factor = 1; factor <= int(sqrt(num)); ++factor){                if (num % factor == 0){                    if(factor != 1)graph[factor].push_back(i);                    if(num / factor != 1)graph[num / factor].push_back(i);                }            }        }        for (auto [k, v]: graph){            const int m = v.size();            for (int i = 1; i < m ; ++i){                uf.union_set(v[0], v[i]);            }        }        int ret = 0;        for (int i = 0; i < n; ++i){            ret = max(ret, uf.get_set_size(i));        }        return ret;    }};`

# Speed up by using Prime Factorization

For example, for the number 8 and 12, the have the common factor of

{2, 4}, actually if they have the common prime factor will be enough as non prime factor can be further split to prime factors. In this example, 4 can be split to 2 * 2. So instead of using all factors, we can only use the prime factor to build the connection. For prime factorization, I borrowed it from [1].

`class UF{    public:    vector<int> roots;    vector<int> sizes;    UF(int n){        roots.assign(n, 0); for (int i = 0; i < n; ++i)roots[i] = i;        sizes.assign(n, 1);            }    int find_set(int x){        return x == roots[x]? x: roots[x] = find_set(roots[x]);    }    void union_set(int x, int y){        int root_x = find_set(x), root_y = find_set(y);        if (root_x == root_y)return;        sizes[root_x] += sizes[root_y];        roots[root_y] = root_x;    }    int get_set_size(int x){        return sizes[x];    }};vector<int> primeFactors(int n){        vector<int>ret;    // Print the number of 2s that divide n    while (n % 2 == 0)    {        ret.push_back(2);        n = n/2;    }     // n must be odd at this point. So we can skip    // one element (Note i = i +2)    for (int i = 3; i <= sqrt(n); i = i + 2)    {        // While i divides n, print i and divide n        while (n % i == 0)        {            ret.push_back(i);            n = n/i;        }    }     // This condition is to handle the case when n    // is a prime number greater than 2    if (n > 2)        ret.push_back(n);    return ret;}class Solution {public:    int largestComponentSize(vector<int>& nums) {        const int n = nums.size();        UF uf(n);        unordered_map<int, vector<int>> graph;        for (int i = 0; i < n; ++i){            int num = nums[i];            auto factors = primeFactors(num);            for (auto &factor: factors)graph[factor].push_back(i);        }        for (auto [k, v]: graph){            const int m = v.size();            for (int i = 1; i < m ; ++i){                    uf.union_set(v[0], v[i]);            }        }        int ret = 0;        for (int i = 0; i < n; ++i){            ret = max(ret, uf.get_set_size(i));        }        return ret;    }};`

# Reference

Data Scientist/MLE/SWE @takemobi

## More from Jimmy Shen

Data Scientist/MLE/SWE @takemobi