思路分析
用队列实现非递归遍历,从未访问的城市入队,依次取出并标记其连通城市入队,队列为空时完成一个省份的遍历。
代码实现
java
public int findCircleNum(int[][] isConnected) {
// 城市数量
int n = isConnected.length;
// 访问标记数组,用于记录每个城市是否被访问过
boolean[] visited = new boolean[n];
// 定义队列用于bfs遍历
Deque<Integer> queue = new LinkedList<>();
// 定义相连的城市数量
int provinceCount = 0;
// 遍历所有城市
for (int i = 0; i < n; i++) {
// 若该城市未被访问过
if (!visited[i]){
// 标记被访问过
visited[i] = true;
// 该城市入队列
queue.offer(i);
// bfs遍历所有与该城市相连的城市
while(!queue.isEmpty()){
// 队首元素出队列
Integer pop = queue.pop();
for (int j = 0; j < n; j++) {
// 若该城市未被访问过且与当前城市相连
if (!visited[j] && isConnected[pop][j] == 1){
// 标记被访问过
visited[j] = true;
// 该城市入队列
queue.offer(j);
}
}
}
// 遍历完所有与该城市相连的城市后,相连的城市数量加1
provinceCount++;
}
}
return provinceCount;
}
复杂度分析
- 时间复杂度:O(n2)(遍历整个矩阵);
- 空间复杂度:O(n)(visited 数组 + 队列,最坏情况队列存储所有城市)。
与树的bfs算法对比
这里贴出bfs算法,方便自己理解该题
java
// 按层输出:返回二维列表,每个子列表对应一层的节点值
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int levelSize = queue.size(); // 关键:当前层的节点数
List<Integer> currentLevel = new ArrayList<>();
// 遍历当前层的所有节点
for (int i = 0; i < levelSize; i++) {
TreeNode curr = queue.poll();
currentLevel.add(curr.val);
// 子节点入队(为下一层准备)
if (curr.left != null) queue.offer(curr.left);
if (curr.right != null) queue.offer(curr.right);
}
result.add(currentLevel); // 将当前层加入结果
}
return result;
}
首先
- 二叉树的层次遍历中,根节点只有一个,所以直接就是
java
queue.offer(root);
while (!queue.isEmpty()) {
....
}
而本题中,多个城市相当于有多个节点,所以多了一层for循环,即第一层for循环
java
for (int i = 0; i < n; i++) {
...
}
- 其次,树的层次遍历中,遍历的次数是该层的节点数,也就是
java
for (int i = 0; i < levelSize; i++) {
...
}
而本题中,每层的节点数都是固定也,因为题目说了是n*n的矩阵,也就是说每层都有n个节点,所以第二层循环要执行n次,也就是
java
for (int j = 0; j < n; j++) {
...
}