1
- # 952. 按公因数计算最大组件大小
1
+ ## 按公因数计算最大组件大小
2
2
3
- ## 题目描述
3
+ ### 问题描述
4
4
5
5
给定一个由不同正整数的组成的非空数组 ` A ` ,考虑下面的图:
6
6
9
9
10
10
返回图中最大连通组件的大小。
11
11
12
+ ** 示例1:**
12
13
13
-
14
- ** 示例 2:**
15
-
14
+ ```
16
15
输入:[4,6,15,35]
17
16
输出:4
17
+ ```
18
+ ![ 示例1] ( /img/Largest-Component-Size-by-Common-Factor1.png )
18
19
19
- ![ 示例 ] ( https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2018/12/01/ex1.png )
20
+ ** 示例2: **
20
21
21
- ** 提示:**
22
+ ```
23
+ 输入: [20,50,9,63]
24
+ 输出: 2
25
+ ```
26
+ ![ 示例2] ( /img/Largest-Component-Size-by-Common-Factor2.png )
22
27
23
- 1 . ` 1 <= A.length <= 20000 `
24
- 2 . ` 1 <= A[i] <= 100000 `
28
+ ** 示例3**
25
29
26
- ## 解法
30
+ ```
31
+ 输入: [2,3,6,7,4,12,21,39]
32
+ 输出: 8
33
+ ```
27
34
28
- ### Naive 版本
35
+ ![ 示例3] ( /img/Largest-Component-Size-by-Common-Factor2.png )
36
+
37
+ ** 提示:**
38
+
39
+ * ` 1 <= A.length <= 20000 `
40
+
41
+ * ` 1 <= A[i] <= 100000 `
42
+
43
+ ### 解法
44
+
45
+ #### Naive 版本
29
46
30
47
这道题涉及到画连线,应当涉及到 union-find。初步解法是:
31
48
32
- * 使用数组,初始化各节点的 root 为自身,并且维护各节点 root 所连通的图的节点数量(size)为 1
33
- * 遍历数组中的每一个数,如果和其他数有大于 1 的公因数,则用 union 方法将他们连在一起
34
- * 在 union 的过程中,由于 union 的对象为各节点的根,因此需要使用 find 方法,并且缩短所涉及的节点和其根(root)的搜索距离,即将该节点与 root 直接连在一起。同时更新 size 数组的对应值
35
- * 在遍历结束后,遍历 size 数组,找到 size 最大的。
49
+ - 使用数组,初始化各节点的 root 为自身,并且维护各节点 root 所连通的图的节点数量(size)为 1
50
+ - 遍历数组中的每一个数,如果和其他数有大于 1 的公因数(也就是不互质) ,则用 union 方法将他们连在一起
51
+ - 在 union 的过程中,由于 union 的对象为各节点的根,因此需要使用 find 方法,并且缩短所涉及的节点和其根(root)的搜索距离,即将该节点与 root 直接连在一起。同时更新 size 数组的对应值
52
+ - 在遍历结束后,遍历 size 数组,找到 size 最大的。
36
53
37
54
``` java
38
55
class Solution {
@@ -111,25 +128,21 @@ class Solution {
111
128
}
112
129
```
113
130
114
- 但是这个代码其实会超时,因为中间的遍历逻辑会耗费很长的时间,时间复杂度为
115
- $$
116
- O(n^2)
117
- $$
118
- 。因此我们需要更快一点的解法。
131
+ 但是这个代码其实会超时,因为中间的遍历逻辑会耗费很长的时间,时间复杂度为 O(n²)。因此我们需要更快一点的解法。
119
132
120
- ### 优化版本
133
+ #### 优化版本
121
134
122
135
由于连通节点的条件是两个节点有公因数,那么他们可以通过这个公因数连在一起,而这个公因数又可以被分解为质因数,这样,我们只需要知道一个节点的质因数有哪些,并且将这些质因数和该节点相连。则对于每一个节点,我们都连接的是其质因数,或者说是质因数所对应的节点,但是本质上我们把这些有相同质因数的节点都连在了一起。具体步骤为:
123
136
124
- * 维护 prime set,找到 100000 以内所有质数(找质数的方法应该都会吧)
125
- * 维护三个数组,分别为:
126
- * 各节点所连接的 root 编号,初始化为节点本身的编号
127
- * 各节点为 root 时,连通图的 size,初始化为 1
128
- * 各质数所连接到的节点对应的 root 的编号,初始化为 -1(因为开始时这些质数都没有和节点连在一起)
129
- * 遍历节点,其中遍历所有质数,如果节点可以整除质数,则将该质数所连通的节点(如果有的话)和当前节点连在一起;并且更新该质数连通 到 新的连通图的 root 的编号。同时更新 root 对应的 size
130
- * 遍历 size 数组,找到值最大的集合
137
+ - 维护 prime set,找到 100000 以内所有质数(找质数的方法应该都会吧)
138
+ - 维护三个数组,分别为:
139
+ - 各节点所连接的 root 编号,初始化为节点本身的编号
140
+ - 各节点为 root 时,连通图的 size,初始化为 1
141
+ - 各质数所连接到的节点对应的 root 的编号,初始化为 -1(因为开始时这些质数都没有和节点连在一起)
142
+ - 遍历节点,其中遍历所有质数,如果节点可以整除质数,则将该质数所连通的节点(如果有的话)和当前节点连在一起;并且更新该质数连通 到 新的连通图的 root 的编号。同时更新 root 对应的 size
143
+ - 遍历 size 数组,找到值最大的集合
131
144
132
- 而题中给定了节点大小小于 100000,因此我们只需要找到 100000 里面的所有质数,并遍历节点将其连接到可以整除该节点的质数上,就等于是完成了有公因数之间的节点的连通。而根据我们上面的推算,遍历每个节点的所有质数时间复杂度是确定的为 O(np),p 为 100000 以内质数数量,即为 O(n),而 union-find 方法的每一个步骤 amortized 复杂度为 O(log* n),一个远小于 log n 的值。因此,我们通过优化了寻找连通边的方法,来达到优化算法的目的。
145
+ 而题中给定了节点值大小小于 100000,因此我们只需要找到 100000 里面的所有质数,并遍历节点将其连接到可以整除该节点的质数上,就等于是完成了有公因数之间的节点的连通。而根据我们上面的推算,遍历每个节点的所有质数时间复杂度是确定的为 O(np),p 为 100000 以内质数数量,即为 O(n),而 union-find 方法的每一个步骤 amortized 复杂度为 O(log* n),一个远小于 log n 的值。因此,我们通过优化了寻找连通边的方法,来达到优化算法的目的。
133
146
134
147
``` java
135
148
class Solution {
@@ -151,6 +164,7 @@ class Solution {
151
164
// find all of its prime factors
152
165
for (Integer prime: primes) {
153
166
if (primes. contains(curr)) {
167
+ // 如果 curr 本身就是质数,则比较简便。
154
168
prime = curr;
155
169
}
156
170
if (curr % prime == 0 ) {
@@ -224,5 +238,3 @@ class Solution {
224
238
}
225
239
```
226
240
227
-
228
-
0 commit comments