基本上算是一道并查集的模板题目了。
这题有两种解法:
- 转化成一个图,用邻接链表表示。然后用DFS或者BFS去搜索
- 用并查集去搜索。求连通分量一般都用这招。
并查集相关的复杂度。相关的解释可以看看零神的讲解——借这个问题科普一下并查集各种情况下的时间复杂度
优化 | 平均时间复杂度 | 最坏时间复杂度 |
---|---|---|
无优化 | O ( log n ) O(\log n) O(logn) | O ( n ) O(n) O(n) |
路径压缩 | O ( α ( n ) ) O(\alpha(n)) O(α(n)) | O ( log n ) O(\log n) O(logn) |
按秩合并 | O ( log n ) O(\log n) O(logn) | O ( log n ) O(\log n) O(logn) |
路径压缩 + 按秩合并 | O ( α ( n ) ) O(\alpha(n)) O(α(n)) | O ( α ( n ) ) O(\alpha(n)) O(α(n)) |
在宇宙可观测的 n n n内(例如宇宙中包含的粒子总数), α ( n ) \alpha(n) α(n) 不会超过 5 5 5
// 这里我们可以把它给的边转化为图。然后用DFS或者BFS去搜索
class Solution {
int[] father;
int[] height;
public int countComponents(int n, int[][] edges) {
// father记录每个节点的根节点,默认为它自己
// height记录它的高度,默认为0
father = new int[n];
height = new int[n];
for(int i = 0; i < n; i++){
father[i] = i;
}
for(int i = 0; i < edges.length; i++){
union(edges[i][0], edges[i][1]);
}
int components = 0;
for(int i = 0; i < n; i++){
if(find(i) == i)
components++;
}
return components;
}
private int find(int x){
if(x != father[x]){
father[x] = find(father[x]);
}
return father[x];
}
private void union(int x, int y){
int fatherX = find(x);
int fatherY = find(y);
if(fatherX != fatherY){
if(height[fatherX] < height[fatherY]){
father[fatherX] = fatherY;
} else if(height[fatherX] > height[fatherY]){
father[fatherY] = fatherX;
} else{
father[fatherY] = fatherX;
height[fatherX]++;
}
}
}
}