547. 省份数量
难度 中等
有 n
个城市,其中一些彼此相连,另一些没有相连。如果城市 a
与城市 b
直接相连,且城市 b
与城市 c
直接相连,那么城市 a
与城市 c
间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n
的矩阵 isConnected
,其中 isConnected[i][j] = 1
表示第 i
个城市和第 j
个城市直接相连,而 isConnected[i][j] = 0
表示二者不直接相连。
返回矩阵中 省份 的数量。
示例 1:
输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出:2
示例 2:
输入:isConnected = [[1,0,0],[0,1,0],[0,0,1]]
输出:3
提示:
1 <= n <= 200
n == isConnected.length
n == isConnected[i].length
isConnected[i][j]
为1
或0
isConnected[i][i] == 1
isConnected[i][j] == isConnected[j][i]
题解
这道题也是一道经典的图论题目,就是套深搜或广搜的模板就行。除了上面两种方法,其实并查集也是一个好的解题方法。
解法一:深搜
class Solution {
public int findCircleNum(int[][] isConnected) {
int c = isConnected.length;//矩阵维度
boolean[] visit = new boolean[c];//访问数组
int count = 0;//记录变量
for(int i = 0; i < c; i++){//行遍历
if(!visit[i]){//该节点没有访问过
count++;
dfs(isConnected, visit, i);//深搜处理该节点
}
}
return count;
}
void dfs(int[][] isConnected, boolean[] visit, int x){//深搜处理该节点
for(int i = 0; i < isConnected[0].length; i++){
if(isConnected[x][i] == 1 && !visit[i]){//遍历相邻节点
visit[i] = true;//把相邻节点置为访问节点
dfs(isConnected, visit, i);//深搜处理该节点
}
}
}
}
解法二:广搜
class Solution {
public int findCircleNum(int[][] isConnected) {
int r = isConnected.length;//矩阵维度
int count = 0;//记录变量
boolean[] visit = new boolean[r];//该节点是否遍历过
Queue<Integer> queue = new LinkedList<Integer>();//广搜辅助队列
for(int i = 0; i < r; i++){
if(!visit[i]){//没有遍历过
count++;
queue.offer(i);//入队
while(!queue.isEmpty()){//队列不为空
int j = queue.poll();//出队
visit[j] = true;//置为true
for(int k = 0; k < r; k++){
if(isConnected[j][k] == 1 && !visit[k]){//遍历相连节点
queue.offer(k);
}
}
}
}
}
return count;
}
}
解法三:并查集
并查集在有些图相关问题上也是可解的,比如这道题是寻找省份数量,就是有多少个集合,通过并查集也可以去解题。也建议大家学一下并查集的模板,大概即使一个步骤:
- 初始化父节点为本身
- 寻找父节点
- 合并父节点
- 判断集合数量
class Solution {
public int findCircleNum(int[][] isConnected) {
int c = isConnected.length;//矩阵维度
int[] parent = new int[c];//父节点数组
for(int i = 0; i < c; i++){//1、初始化父节点为本身
parent[i] = i;
}
for(int i = 0; i < c; i++){//行遍历
for(int j = i + 1; j < c; j++){//列遍历
if(isConnected[i][j] == 1){//相连
union(parent, i, j);//合并父节点
}
}
}
int count = 0;
for(int i = 0; i < c; i++){//4、判断集合数量
if(parent[i] == i){//每个集合只有一个根节点,如果父节点等于本身,就代表一个集合
count++;
}
}
return count;
}
int find(int[] parent, int x){//2、寻找父节点
return x == parent[x] ? x : find(parent, parent[x]);
}
void union(int[] parent, int index1, int index2){//3、合并父节点
parent[find(parent, index1)] = find(parent, index2);
}
}