LeetCode 952 - Largest Component Size by Common Factor


https://leetcode.com/problems/largest-component-size-by-common-factor/
Given a non-empty array of unique positive integers A, consider the following graph:
  • There are A.length nodes, labelled A[0] to A[A.length - 1];
  • There is an edge between A[i] and A[j] if and only if A[i] and A[j] share a common factor greater than 1.
Return the size of the largest connected component in the graph.

    Example 1:
    Input: [4,6,15,35]
    Output: 4
    
    
    Example 2:
    Input: [20,50,9,63]
    Output: 2
    
    
    Example 3:
    Input: [2,3,6,7,4,12,21,39]
    Output: 8
    
    
    Note:
    1. 1 <= A.length <= 20000
    2. 1 <= A[i] <= 100000

    Approach 1: Union-Find
    https://blog.csdn.net/fuxuemingzhu/article/details/85015411
    很简单。任何两个数之间有相同的因子,就连接到一起,换句话说,可以把每个数字和它的所有因子进行链接,最后统计哪个因子上面的数字最多即可。

    所以使用的方法是并查集,但是并不是把数组里面的两个元素进行合并,而是把每个数字和它所有的因子进行union。最后统计的数字也是某个因子上面的链接的数字的个数,因为这就是一条链的意思。
    https://zxi.mytechroad.com/blog/graph/leetcode-952-largest-component-size-by-common-factor/
    Time complexity: O(Σsqrt(A[i]))
    Space complexity: O(max(A))

      DSU(int n): p_(n) {
        for (int i = 0; i < n; ++i)
          p_[i] = i;
      }
      
      void Union(int x, int y) {
        p_[Find(x)] = p_[Find(y)];
      }
      
      int Find(int x) {
        if (p_[x] != x) p_[x] = Find(p_[x]);
        return p_[x];
      }
    private:
      vector<int> p_;
    };
    class Solution {
    public:
      int largestComponentSize(vector<int>& A) {    
        int n = *max_element(begin(A), end(A));
        DSU dsu(n + 1);
        for (int a : A) {
          int t = sqrt(a);
          for (int k = 2; k <= t; ++k)
            if (a % k == 0) {
              dsu.Union(a, k);
              dsu.Union(a, a / k);
            }
        }
        unordered_map<int, int> c;
        int ans = 1;
        for (int a : A)
          ans = max(ans, ++c[dsu.Find(a)]);    
        return ans;
      }
    https://leetcode.com/problems/largest-component-size-by-common-factor/discuss/200959/Simplest-Solution-(Union-Find-only)-No-Prime-Calculation
        public int largestComponentSize(int[] A) {
            int N = A.length;
            Map<Integer, Integer> map = new HashMap<>();// key is the factor, val is the node index
            UF uf = new UF(N);
            for (int i = 0; i < N; i++){
                int a = A[i];
                for (int j = 2; j * j <= a; j++){
                    if (a % j == 0){
                        if (!map.containsKey(j)){//this means that no index has claimed the factor yet
                            map.put(j, i);
                        }else{//this means that one index already claimed, so union that one with current
                            uf.union(i, map.get(j));
                        }
                        if (!map.containsKey(a/j)){
                            map.put(a/j, i);
                        }else{
                            uf.union(i, map.get(a/j));
                        }
                    }
                }
                if (!map.containsKey(a)){//a could be factor too. Don't miss this
                    map.put(a, i);
                }else{
                    uf.union(i, map.get(a));
                }
            }
            return uf.max;
        }
    

    https://www.acwing.com/solution/leetcode/content/646/
    Let W = \max(A[i]), and R = \sqrt{W}. For each value A[i], there is at most one prime factor p \geq R dividing A[i]. Let's call A[i]'s "big prime" this p, if it exists.
    This means that there are at most R + A\text{.length} unique prime divisors of elements in A: the big primes correspond to a maximum of A\text{.length} values, and the small primes are all less than R, so there's at most R of them too.
    Algorithm
    Factor each A[i] into prime factors, and index every occurrence of these primes. (To save time, we can use a sieve. Please see this article's comments for more details.)
    Then, use a union-find structure to union together any prime factors that came from the same A[i].
    Finally, we can count the size of each component, by inspecting and counting the id of the component each A[i] belongs to.
    • Time Complexity: O(N\sqrt{W}) where N is the length of A, and W = \max(A[i]).
    • Space Complexity: O(N)
      public int largestComponentSize(int[] A) {
        int N = A.length;

        // factored[i] = a list of unique prime factors of A[i]
        ArrayList<Integer>[] factored = new ArrayList[N];
        for (int i = 0; i < N; ++i) {
          factored[i] = new ArrayList<Integer>();
          int d = 2, x = A[i];
          while (d * d <= x) {
            if (x % d == 0) {
              while (x % d == 0)
                x /= d;
              factored[i].add(d);
            }

            d++;
          }

          if (x > 1 || factored[i].isEmpty())
            factored[i].add(x);
        }

        // primesL : a list of all primes that occur in factored
        Set<Integer> primes = new HashSet();
        for (List<Integer> facs : factored)
          for (int x : facs)
            primes.add(x);

        int[] primesL = new int[primes.size()];
        int t = 0;
        for (int x : primes)
          primesL[t++] = x;

        // primeToIndex.get(v) == i iff primes[i] = v
        Map<Integer, Integer> primeToIndex = new HashMap();
        for (int i = 0; i < primesL.length; ++i)
          primeToIndex.put(primesL[i], i);

        DSU dsu = new DSU(primesL.length);
        for (List<Integer> facs : factored)
          for (int x : facs)
            dsu.union(primeToIndex.get(facs.get(0)), primeToIndex.get(x));

        int[] count = new int[primesL.length];
        for (List<Integer> facs : factored)
          count[dsu.find(primeToIndex.get(facs.get(0)))]++;

        int ans = 0;
        for (int x : count)
          if (x > ans)
            ans = x;
        return ans;
      }
    class DSU {
      int[] parent;

      public DSU(int N) {
        parent = new int[N];
        for (int i = 0; i < N; ++i)
          parent[i] = i;
      }

      public int find(int x) {
        if (parent[x] != x)
          parent[x] = find(parent[x]);
        return parent[x];
      }

      public void union(int x, int y) {
        parent[find(x)] = find(y);
      }

    }
    https://leetcode.com/problems/largest-component-size-by-common-factor/discuss/200546/Prime-Factorization-and-Union-Find
    1. Calculate all prime numbers less than 100000.
    2. For each number in A, we say A[i]
      a. Do Prime Factorization(Brute force using the primes set in step 1), we say the prime factor is p.
      b. If p has presented in the primeToIndex, union i and primeToIndex[p].
      c. Update primeToIndex[p] to i.
    3. Return the maximum count.
    Time complexity: O(NP), where P is the count of prime numbers < 100000. I think this is an upperbound time complexity.
        int max = 0;
        public int largestComponentSize(int[] A) {
            boolean[] isPrime = new boolean[100001];
            Arrays.fill(isPrime, true);
            Set<Integer> primes = new HashSet<>();
            // all primes less than 100000
            for (int i = 2; i <= 100000; i++) {
                if (isPrime[i]) {
                    primes.add(i);
                    for (int j = 2; j * i <= 100000; j++) {
                        isPrime[j * i] = false;
                    }
                }
            }
            int n = A.length;
            int[] counts = new int[n];
            int[] parents = new int[n];
            int[] primeToIndex = new int[100001];
            Arrays.fill(primeToIndex, -1);
            for (int i = 0; i < n; i++) {
                parents[i] = i;
                counts[i] = 1;
            }
            for (int i = 0; i < n; i++) {
                int a = A[i];
                for (int p : primes) {
                    if (primes.contains(a)) { // Optimization
                        p = a;
                    }
                    if (a % p == 0) {
                        if (primeToIndex[p] > -1) {
                            union(parents, counts, primeToIndex[p], i);
                        }
                        primeToIndex[p] = i;
                        while (a % p == 0) {
                            a /= p;
                        }
                    }
                    if (a == 1) {
                        break;
                    }
                }
            }
            return max;
        }
        private int find(int[] parents, int a) {
            if (parents[a] != a) {
                parents[a] = find(parents, parents[a]);
            }
            return parents[a];
        }
        private void union(int[] parents, int[] counts, int a, int b) {
            int root1 = find(parents, a), root2 = find(parents, b);
            if (root1 == root2) {
                return;
            }
            int count = counts[root2] + counts[root1];
            max = Math.max(count, max);
            parents[root1] = root2;
            counts[root2] = count;
        }
    

    https://zhanghuimeng.github.io/post/leetcode-952-largest-component-size-by-common-factor/
    • 埃式筛法,map存储分解结果,普通并查集:1324ms
    • 埃式筛法,map存储分解结果,size优化并查集:1452, 1848ms
    • 欧拉筛法,map存储分解结果,普通并查集:TLE, 1868ms
    • 埃式筛法(减少素数),map存储分解结果,普通并查集:144ms
    • 素数打表,map存储分解结果,普通并查集:132ms
    • 素数打表,手写链表,普通并查集:132ms
    • 首先打一个质数表。
      • 我之前认为需要打[1, 100000]范围内的质数(事实证明,一共有九千多个),但事实上不需要,只要打[1, sqrt(100000)]范围内的素数就可以了。在做质因数分解的时候,如果用上述范围内的质数没能约到1,则剩下的数必然是个大素数,不需要打表打到这个范围。
      • 打表可以用埃式筛法或者欧拉筛法(我之前在某次模拟赛中做过类似的题)。
    • 然后对每个数值作质因数分解,对每个质数开一个链表(或者类似的结构),如果一个质数是某个数的因数,就把这个数(的index)放到链表中。
    • 然后对每条链表中的值在并查集中作合并操作。
    • 最后找出并查集中最大的集合。
        int largestComponentSize(vector<int>& A) {
            int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 
                      83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 
                      173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 
                      269, 271, 277, 281, 283, 293, 307, 311, 313, 317};
            int m = sizeof(primes) / sizeof(int);
            // 质因数分解,插入对应的vector
            map<int, vector<int>> primeMap;
            n = A.size();
            for (int i = 0; i < n; i++) {
                int x = A[i];
                int j = 0;
                while (j < m) {
                    if (x == 1) break;
                    while (j < m && x % primes[j] != 0) j++;
                    if (j >= m) break;
                    while (x % primes[j] == 0) x /= primes[j];
                    primeMap[primes[j]].push_back(i);
                    j++;
                }
                if (x != 1) primeMap[x].push_back(i);
            }
            // 合并每个质因数对应的所有数
            init();
            for (auto const& p: primeMap) {
                if (p.second.size() > 1) {
                    int fa0 = fa(p.second[0]);
                    for (int i = 1; i < p.second.size(); i++) {
                        fa0 = merge(fa0, p.second[i]);
                    }
                }
            }
            // 找到最大的集合,输出结果
            int maxn = -1;
            for (int i = 0; i < n; i++)
                maxn = max(maxn, size(i));
            return maxn;
        }


    http://www.noteanddata.com/leetcode-952-Largest-Component-Size-by-Common-Factor-java-solution-note.html
        public int largestComponentSize(int[] a) {
            UnionFind uf = new UnionFind(a.length);
            Map<Integer, Set<Integer>> map = new HashMap<>(); // index--> factor set
            for(int i = 0; i < a.length; ++i) {
                map.put(i, factorSet(a[i]));
            }
            
            Map<Integer, Set<Integer>> rmap = new HashMap<>(); // factor--> index set
            for(Map.Entry<Integer, Set<Integer>> entry: map.entrySet()) {
                int i = entry.getKey();
                Set<Integer> set = entry.getValue();
                for(int factor: set) {
                    Set<Integer> indexSet = rmap.get(factor);
                    if(null == indexSet) {
                        indexSet = new HashSet<>();
                        rmap.put(factor, indexSet);
                    }
                    indexSet.add(i);
                }
            }
            
            for(Map.Entry<Integer, Set<Integer>> entry: rmap.entrySet()) {
                Set<Integer> set = entry.getValue();
                int v = -1;
                for(int i: set) {//??
                    v = i;
                    break;
                }
                for(int i: set) {
                    uf.union(i, v);
                }
            }        
            
            Map<Integer, Integer> idCount = new HashMap<>();
            for(int i = 0; i < a.length; ++i) {
                int id = uf.root(i);
                int count = idCount.getOrDefault(id, 0);
                idCount.put(id, count+1);
            }
            
            int max = 0;
            for(int v : idCount.values()) {
                max = Math.max(max, v);
            }
           return max;
        }
        
        
        public Set<Integer> factorSet(int a) {
            Set<Integer> set = new HashSet<>();
            set.add(a);
            int upper = (int)Math.sqrt(a);
            for(int i = 2; i <= upper && i <= a; ++i) {
                while(a%i == 0) {
                    set.add(i);
                    a /= i;
                    if(a != 1) {
                        set.add(a);    
                    }
                    
                }
            }
            return set;
        }
    

    https://leetcode.com/problems/largest-component-size-by-common-factor/discuss/203266/Java-solution-without-Prime-Factor!

    Labels

    LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

    Popular Posts