力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
题目描述
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。 省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。 给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。 返回矩阵中 省份 的数量。
这个问题描述了一个典型的图论问题,涉及到找出图中的连通分量的数量。在这个场景中,每个城市可以看作图中的一个节点,如果两个城市直接相连,那么这两个城市间就有一条边。问题的目标是找出图中有多少个完全独立的连通分量,即“省份”。
给定的矩阵 isConnected
实际上是一个邻接矩阵,表示了城市之间的连接状态。isConnected[i][j] = 1
表示城市 i
和城市 j
直接相连,而 isConnected[i][j] = 0
表示两者不直接相连。
解题方法
为了解决这个问题,可以使用深度优先搜索(DFS)或广度优先搜索(BFS)算法来遍历图,并找出所有连通分量。
使用深度优先搜索(DFS)
- 初始化:创建一个标记数组,用于记录每个城市是否已被访问。
- 遍历每个城市:对于每个城市,如果它还没有被访问,那么从这个城市开始进行一次深度优先搜索,这代表了一个新的省份。
- 深度优先搜索:在 DFS 过程中,访问当前城市的所有未访问邻接城市,将其标记为已访问。
- 计数:每完成一次完整的 DFS,省份的数量加一。
class Solution {
public:
void dfs(int j,vector<vector<int>>&graph,vector<bool>&vis){
for(int i=0;i<graph.size();++i){
if(!vis[i]&&graph[j][i]==1){
vis[i]=true;
dfs(i,graph,vis);
}
}
}
int findCircleNum(vector<vector<int>>& isConnected) {
int n=isConnected.size();
vector<bool>vis(n,false);
int ans=0;
for(int j=0;j<isConnected.size();j++){
if(!vis[j]){
ans++;
dfs(j,isConnected,vis);
}
}
return ans;
}
};
使用广度优先搜索(BFS)
- 初始化:创建一个标记数组,用于记录每个城市是否已被访问。
- 遍历每个城市:对于每个未访问的城市,进行一次广度优先搜索。
- 广度优先搜索:使用队列来实现 BFS。将当前城市的所有未访问邻接城市加入队列,并标记为已访问。
- 计数:每完成一次完整的 BFS,省份的数量加一。
class Solution {
public:
int bfs(vector<vector<int>>&graph){
int size=graph.size();
int count=0;
//记录访问过的城市
vector<bool>vis(size,false);
//对每个城市进行遍历
for(int i=0;i<size;i++){
//如果是第一次访问当前城市则对这个城市的所有相连城市进行遍历
if(!vis[i]){
queue<int>q;
q.push(i);
vis[i]=true;
//广度遍历所有相连城市并放入队列中
while(!q.empty()){
int curr=q.front();q.pop();
for(int j=0;j<size;++j){
if(!vis[j]&&graph[curr][j]==1){
vis[j]=true;
q.push(j);
}
}
}
count++;
}
}
return count;
}
int findCircleNum(vector<vector<int>>& isConnected) {
return bfs(isConnected);
}
};
代码解释
- BFS 函数:该函数实现广度优先搜索来找出图中连通分量的数量。
- 外层循环:遍历每个节点,开始新的 BFS 搜索未访问的节点。
- 内部循环:对于当前节点
curr
,遍历所有其他节点,检查是否存在边(graph[curr][j] == 1
),并且该节点未被访问(!vis[j]
)。如果是,就将其加入队列并标记为已访问。 - 计数:每完成一次 BFS 循环,计数器
count
增加,代表找到一个新的连通分量(省份)。