Editorial
Core insight
Largest Component Size by Common Factor · Graph Traversal Patterns (DFS & BFS)
Core Insight for Largest Component Size by Common Factor
The core insight that allows us to bypass the comparison is prime factorization.
If number and number share a common factor , they belong to the same component. This implies transitivity: if shares a factor with , and shares a factor with , then , , and are in the same component.
Instead of connecting numbers directly to each other, we can connect each number to its factors.
- If we have the number 6, it has factors 2 and 3. We can conceptually draw edges and .
- If we have the number 15, it has factors 3 and 5. We draw edges and .
- Because 6 and 15 both connect to the factor 3, they become part of the same connected component ().
Visual Description:
Imagine the DSU structure as a forest of trees. Initially, every integer from 1 up to the maximum value in nums is its own root. When we process a number from the input array, say 14, we calculate its prime factors (2 and 7). We perform a union operation merging the set containing 14, the set containing 2, and the set containing 7. As we process more numbers, these sets merge further. Finally, the "size" of a component is determined by how many numbers from the original nums array map to the same root parent in the DSU structure.
By unioning numbers with their factors, we implicitly build the connected components without ever iterating over pairs of numbers.
Deep dive
Full breakdown
Full reasoning, pitfalls, and implementation flow
LeetCode 952: Largest Component Size by Common Factor Solution & Explanation
Problem Overview
TL;DR: The optimal solution decomposes each number into its prime factors and uses a Union-Find (Disjoint Set Union) data structure to group numbers that share common prime factors, subsequently counting the size of the largest group.
In the LeetCode 952 problem, "Largest Component Size by Common Factor," you are provided with an array of unique positive integers. These integers represent nodes in a graph. An undirected edge exists between two nodes if they share a common factor greater than 1 (i.e., their greatest common divisor is greater than 1). The objective is to determine the size of the largest connected component in this implicitly defined graph.
Brute Force Approach for Largest Component Size by Common Factor
The naive approach attempts to build the graph explicitly by checking every possible pair of numbers to see if an edge exists between them.
- Initialize an adjacency list or matrix for a graph with nodes.
- Iterate through every pair of indices from the input array
nums. - Calculate the Greatest Common Divisor (GCD) of
nums[i]andnums[j]. - If , add an edge between node and node .
- After building the graph, perform a standard DFS or BFS on every unvisited node to find the size of its connected component.
- Return the maximum size found.
Pseudo-code:
max_size = 0
visited = set()
graph = build_empty_graph(nums.length)
for i from 0 to nums.length:
for j from i + 1 to nums.length:
if gcd(nums[i], nums[j]) > 1:
add_edge(graph, i, j)
for i from 0 to nums.length:
if i not in visited:
component_size = dfs(graph, i, visited)
max_size = max(max_size, component_size)
return max_sizeTime Complexity Analysis: The time complexity is dominated by the pair-wise comparison. There are pairs. Calculating GCD takes logarithmic time relative to the value of the numbers (). Total Complexity: .
Why it fails: Given the constraints, can be up to . results in pairs. Combined with the GCD overhead, this far exceeds the typical operation limit (approx ) allowed by LeetCode, resulting in a Time Limit Exceeded (TLE) error.
Algorithm Strategy: Graph - Union-Find (DSU)
- Identify the Range: Determine the maximum value () in the
numsarray. This defines the size of our DSU array, as we need to handle all potential factors up to this maximum. - Initialize DSU: Create a Union-Find data structure capable of handling elements from to .
- Factorize and Union: Iterate through each number
numin the input arraynums.- Find all prime factors of
num. We can do this by iterating from up to . - If divides
num, then both and are factors. - Perform
union(num, d)andunion(num, num/d). This effectively groups the numbernumwith all other numbers that share the factor or .
- Find all prime factors of
- Count Components:
- Initialize a frequency map (hash map).
- Iterate through the original
numsarray one last time. - For each
num, find its representative root usingfind(num). - Increment the count for this root in the frequency map.
- Result: The maximum value in the frequency map is the size of the largest connected component.
Execution Flow
Let's trace nums = [4, 6, 15, 35]. Max value is 35. Initialize DSU for .
- Process 4:
- Factors: 2.
union(4, 2). Set: .
- Process 6:
- Factors: 2, 3.
union(6, 2). Set merges with . New Set: .union(6, 3). Set merges with . New Set: .
- Process 15:
- Factors: 3, 5.
union(15, 3). Set merges with . New Set: .union(15, 5). Set merges with . New Set: .
- Process 35:
- Factors: 5, 7.
union(35, 5). Set merges with previous large set.union(35, 7).- All numbers are now indirectly connected.
- Count:
find(4)Root A. Count[Root A] = 1.find(6)Root A. Count[Root A] = 2.find(15)Root A. Count[Root A] = 3.find(35)Root A. Count[Root A] = 4.
- Result: Max count is 4.
Proof of Correctness
The correctness relies on the mathematical definition of the problem edges. An edge exists between and if . This implies there exists a prime such that and .
Our algorithm performs union(A, p) and union(B, p). Due to the transitive property of the Union-Find data structure, if is connected to and is connected to , then is connected to . Thus, any two numbers that share a common factor will end up in the same set. Since connectivity is transitive (if and , then ), the DSU correctly aggregates all elements belonging to the same connected component.
Pattern Reuse Notes
The Graph - Union-Find pattern is highly reusable for connectivity problems involving dynamic grouping or cycle detection.
- LeetCode 200: Number of Islands: While typically DFS/BFS, this can be solved with DSU by unioning adjacent land cells.
- LeetCode 261: Graph Valid Tree: Uses DSU to detect cycles; a valid tree must have edges and no cycles.
- LeetCode 305: Number of Islands II: A classic dynamic connectivity problem where DSU is essential to merge islands as land is added.
- LeetCode 323: Number of Connected Components in an Undirected Graph: The direct definition of finding component counts using DSU.
Feynman coach · Before you peek at the code
Can you explain the core insight in your own words?
If you can explain it before reading code, you’re far more likely to recall it under interview pressure.
Reference Implementation
C++ Solution for LeetCode 952
1#include <vector>
2#include <numeric>
3#include <algorithm>
4#include <cmath>
5#include <unordered_map>
6
7using namespace std;
8
9class DSU {
10public:
11 vector<int> parent;
12
13 DSU(int n) {
14 parent.resize(n + 1);
15 iota(parent.begin(), parent.end(), 0);
16 }
17
18 int find(int x) {
19 if (parent[x] != x) {
20 parent[x] = find(parent[x]); // Path compression
21 }
22 return parent[x];
23 }
24
25 void unite(int x, int y) {
26 int rootX = find(x);
27 int rootY = find(y);
28 if (rootX != rootY) {
29 parent[rootX] = rootY; // Simple union
30 }
31 }
32};
33
34class Solution {
35public:
36 int largestComponentSize(vector<int>& nums) {
37 int maxVal = *max_element(nums.begin(), nums.end());
38 DSU dsu(maxVal);
39
40 // Union numbers with their factors
41 for (int num : nums) {
42 for (int factor = 2; factor * factor <= num; ++factor) {
43 if (num % factor == 0) {
44 dsu.unite(num, factor);
45 dsu.unite(num, num / factor);
46 }
47 }
48 }
49
50 // Count frequency of each component's root
51 unordered_map<int, int> componentSize;
52 int maxSize = 0;
53
54 for (int num : nums) {
55 int root = dsu.find(num);
56 componentSize[root]++;
57 maxSize = max(maxSize, componentSize[root]);
58 }
59
60 return maxSize;
61 }
62};Java Solution for LeetCode 952
1import java.util.HashMap;
2import java.util.Map;
3
4class Solution {
5 class DSU {
6 int[] parent;
7
8 public DSU(int n) {
9 parent = new int[n + 1];
10 for (int i = 0; i <= n; i++) {
11 parent[i] = i;
12 }
13 }
14
15 public int find(int x) {
16 if (parent[x] != x) {
17 parent[x] = find(parent[x]); // Path compression
18 }
19 return parent[x];
20 }
21
22 public void union(int x, int y) {
23 int rootX = find(x);
24 int rootY = find(y);
25 if (rootX != rootY) {
26 parent[rootX] = rootY;
27 }
28 }
29 }
30
31 public int largestComponentSize(int[] nums) {
32 int maxVal = 0;
33 for (int num : nums) maxVal = Math.max(maxVal, num);
34
35 DSU dsu = new DSU(maxVal);
36
37 // Iterate over each number and union with its factors
38 for (int num : nums) {
39 for (int factor = 2; factor * factor <= num; factor++) {
40 if (num % factor == 0) {
41 dsu.union(num, factor);
42 dsu.union(num, num / factor);
43 }
44 }
45 }
46
47 // Count the size of components based on roots of numbers in nums
48 Map<Integer, Integer> countMap = new HashMap<>();
49 int maxComponent = 0;
50
51 for (int num : nums) {
52 int root = dsu.find(num);
53 int count = countMap.getOrDefault(root, 0) + 1;
54 countMap.put(root, count);
55 maxComponent = Math.max(maxComponent, count);
56 }
57
58 return maxComponent;
59 }
60}Python Solution for LeetCode 952
1class Solution:
2 def largestComponentSize(self, nums: list[int]) -> int:
3 max_val = max(nums)
4
5 # DSU Implementation using a list
6 parent = list(range(max_val + 1))
7
8 def find(x):
9 if parent[x] != x:
10 parent[x] = find(parent[x]) # Path compression
11 return parent[x]
12
13 def union(x, y):
14 rootX = find(x)
15 rootY = find(y)
16 if rootX != rootY:
17 parent[rootX] = rootY
18
19 # Union numbers with their factors
20 for num in nums:
21 limit = int(num**0.5)
22 for factor in range(2, limit + 1):
23 if num % factor == 0:
24 union(num, factor)
25 union(num, num // factor)
26
27 # Count component sizes
28 from collections import defaultdict
29 count_map = defaultdict(int)
30 max_size = 0
31
32 for num in nums:
33 root = find(num)
34 count_map[root] += 1
35 max_size = max(max_size, count_map[root])
36
37 return max_size