Given a non-empty array of unique positive integers A
, consider the following graph:
- There are
A.length
nodes, labelledA[0]
toA[A.length - 1];
- There is an edge between
A[i]
andA[j]
if and only ifA[i]
andA[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 <= A.length <= 20000
1 <= A[i] <= 100000
這道題給了一個非空正數數組A,現在將每個數字看作一個結點,定義兩個結點相連的條件是兩個數字共享一個大於1的因子,求最大的相連的結點個數。這道題看似像一個圖的問題,其實跟圖並沒有太大的關系,本質上就是群組問題,這種歸組類的問題,最典型的就是島嶼問題(例如 Number of Islands II),很適合使用聯合查找 Union Find 來做,也叫並查集,LeetCode 中有很多道可以使用這個方法來做的題,比如 Friend Circles,Graph Valid Tree,Number of Connected Components in an Undirected Graph,和 Redundant Connection 等等。都是要用一個 root 數組,每個點開始初始化為不同的值,如果兩個點屬於相同的組,就將其中一個點的 root 值賦值為另一個點的位置,這樣只要是相同組里的兩點,通過 find 函數得到相同的值。這里也是一樣,我們希望把所有至少共享一個大於2的因子的數字都放到一個群組中,那么初始化數組的大小就應該是數組A中最大的數字加1,因為數組序列是0開頭的。先遍歷一遍數組A,找出最大數字,然后建立 root 數組初始化為不同的群組。之后遍歷數組A,對於每個數字,找出其所有大於2的因子,由於因子都是成對出現的,所以只需要從其平方根遍歷到2即可,每當找到一對因子,分別將其跟原數組合並起來,注意在更新 root 數組的時候,對於每個數字都要調用 find 函數,這里希望將同一個群組的 root 值都更新為相同的值,這樣方便后面統計每個群組中結點的個數。當所有的因子都合並完成了之后,下面進行查找操作,使用一個 HashMap 來建立群組祖先結點值和結點個數之間的映射。對於每個遍歷到的數組,通過 find 函數查找祖先值,然后將其在 HashMap 中映射值自增1,然后用更新后的值來更新結果 res 即可,參見代碼如下:
class Solution {
public:
int largestComponentSize(vector<int>& A) {
int n = 0, mx = 0, res = 0;
unordered_map<int, int> m;
for (int num : A) mx = max(mx, num);
vector<int> root(mx + 1);
for (int i = 1; i <= mx; ++i) root[i] = i;
for (int num : A) {
for (int d = sqrt(num); d >= 2; --d) {
if (num % d == 0) {
root[find(root, num)] = root[find(root, d)];
root[find(root, num)] = root[find(root, num / d)];
}
}
}
for (int num : A) {
res = max(res, ++m[find(root, num)]);
}
return res;
}
int find(vector<int>& root, int x) {
return root[x] == x ? x : (root[x] = find(root, root[x]));
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/952
參考資料:
https://leetcode.com/problems/largest-component-size-by-common-factor/