题目链接:LeetCode 547
题目思路:计算图中的连通分量的个数,通过深度搜索实现,或者并查集实现。
方法1 深度优先搜索
深度优先搜索,时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)。
class Solution {
public int findCircleNum(int[][] isConnected) {
int cities = isConnected.length;
// 记录访问过的城市下标
boolean[] visited = new boolean[cities];
int proviences = 0;
for(int i = 0; i < cities; i++)
{
if(!visited[i])
{
// 如果没访问过就对当前的下标进行染色操作
dfs(isConnected, visited, cities, i);
proviences++;
}
}
return proviences;
}
public void dfs(int[][] isConnected, boolean[] visited, int cities, int i)
{
for(int j = 0; j < cities; j++)
{
// 如果两点之间是可达的,并且j是未访问过的城市,进行递归的染色
if(isConnected[i][j] == 1 && !visited[j])
{
visited[j] = true;
dfs(isConnected, visited, cities, j);
}
}
}
}
方法2 并查集
在并查集初始化的时候,每个城市都属于不同的连通分量,当两个城市之间有相连的关系时,将他们修改为同一个集合中去,进行合并,并最终统计连通分量的总数。时间复杂度 O ( n 2 l o g n ) O(n^2logn) O(n2logn),空间复杂度 O ( n ) O(n) O(n)。
class Solution {
public int findCircleNum(int[][] isConnected) {
int cities = isConnected.length;
int[] parent = new int[cities];
// 并查集的初始化,认为自己是一个集合
for(int i = 0; i < cities; i++)
parent[i] = i;
for(int i = 0; i < cities; i++)
{
// 避免遍历重复元素
for(int j = i + 1; j < cities; j++)
{
if(isConnected[i][j] == 1)
union(parent, i, j);
}
}
int proviences = 0;
for(int i = 0; i < cities; i++)
{
if(parent[i] == i)
{
proviences++;
}
}
return proviences;
}
public void union(int[] parent, int i, int j)
{
parent[find(parent, i)] = find(parent, j);
}
public int find(int[] parent, int index)
{
// 不是根节点的情况下
if(parent[index] != index)
{
// 递归的进行路径压缩,都压缩到根节点的下边
parent[index] = find(parent, parent[index]);
}
return parent[index];
}
}