1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution {
public long countPairs(int n, int[][] edges) {
boolean[] visited = new boolean[n];
Map<Integer, List<Integer>> neighbors = new HashMap<>();
for (int[] edge : edges) {
neighbors.computeIfAbsent(edge[0], (key) -> new ArrayList<>()).add(edge[1]);
neighbors.computeIfAbsent(edge[1], (key) -> new ArrayList<>()).add(edge[0]);
}
long ans = 0, remainingNodes = n;
for (int i = 0; i < n; i++) {
if (!visited[i]) {
long groupSize = dfs(i, neighbors, visited);
ans += groupSize * (remainingNodes - groupSize);
remainingNodes -= groupSize;
}
}
return ans;
}

private int dfs(int currNode, Map<Integer, List<Integer>> neighbors, boolean[] visited) {
visited[currNode] = true;
int ans = 1;
if (!neighbors.containsKey(currNode)) {
return ans;
}
for (Integer neighbor : neighbors.get(currNode)) {
if (!visited[neighbor]) {
ans += dfs(neighbor, neighbors, visited);
}
}
return ans;
}
}

思路很简单, 统计每个小团体node的个数. 然后计算每个小团体的node个数乘以剩余的node个数, 就是这个小团体的不可达的pair的个数. 然后把所有小团体的不可达的pair的个数加起来就是答案. 这个思路很重要, 我之前想的是把所有的小团体的个数统计记录, 然后使用nested for loop来计算每个小团体的不可达的pair的个数, 这样的话时间复杂度是O(n^2), 会超时. 这个思路是O(n), 但是我还是没想出来. 这里的思路是知道第一个小团体的groupSize后, 这个size乘上剩下的node的个数就是能和第一个小团体中node构成pair的个数. 为了防止重复计算, 我们把第一个小团体的node个数从remaningNodes中减去. 之后是得到第二个小团体的groupSize,
同样乘以剩余node的个数(此时的个数已经抛去第一个小团体的node). 这个方法是O(n)时间复杂度的.

时间复杂度: O(n + m), n是node的个数, m是edge的个数. 创建map需要O(m), visited数组是O(n).
空间复杂度: O(n + e) map + visited数组.