开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第32天,点击查看活动详情 这也是第41篇文章
前言
上一篇文章中我提到了深度优先搜索,那也必然不能漏掉广度优先搜索!很多和图、树相关的问题只要能用dfs做,也肯定可以用bfs做,反之亦然。这两种算法思想各有千秋,看读者更习惯用哪个了。
dfs与bfs的一些比较
- 深度优先搜索基于栈,而广度优先搜索基于队列
- 算法名字也说明了:dfs讲究深度,给定一棵树,该算法会从根节点开始,直到到叶子结点后才遍历其他路径;bfs则是每到一层,都将该层遍历完再去下一层。
(印象中我用dfs比较多,但也不是没用bfs写过题,但我在力扣题单搜的时候,写着bfs标签的题我都是用dfs或者递归之类的方法做的。。我也不知道为什么。。搜了20分钟什么都没搜出来,最后求助知乎和CSDN,找到了几题经典题,一看我也刚好写过bfs的解法)
剑指 Offer II 116. 省份数量
题目
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
思路
这里体现了典型的bfs实现。每次将当前元素入队,然后将已有元素逐个出队并遍历。
代码实现
class Solution {
public int findCircleNum(int[][] isConnected) {
int cities=isConnected.length;
boolean[] visited=new boolean[cities];
int provinces=0;
Queue<Integer> queue=new LinkedList<Integer>();
for (int i=0;i<cities;i++) {
if (!visited[i]){
queue.offer(i);
while (!queue.isEmpty()) {
int j=queue.poll();
visited[j]=true;
for (int k=0; k<cities;k++) {
if (isConnected[j][k]==1&&!visited[k]) {
queue.offer(k);
}
}
}
provinces++;
}
}
return provinces;
}
}
公交路线
题目
给你一个数组
routes,表示一系列公交线路,其中每个routes[i]表示一条公交线路,第i辆公交车将会在上面循环行驶。
- 例如,路线
routes[0] = [1, 5, 7]表示第0辆公交车会一直按序列1 -> 5 -> 7 -> 1 -> 5 -> 7 -> 1 -> ...这样的车站路线行驶。现在从
source车站出发(初始时不在公交车上),要前往target车站。 期间仅可乘坐公交车。求出 最少乘坐的公交车数量 。如果不可能到达终点车站,返回
-1。
思路
这题是道困难题,bfs只是其中一步,它关键是要建图,求最短路径,找最短路径。
代码实现(附部分注释)
class Solution {
public int numBusesToDestination(int[][] routes, int source, int target) {
if(source==target) return 0;//起终点相同
int n=routes.length;//公交路线的数量
//两条线路之间是否有公共站点
boolean [][] edges=new boolean [n][n];
//site:站点 list:经过该站点的公交车列表
Map<Integer,List<Integer>> staTobus=new HashMap<>();
//第一层循环:第i辆公交车
for(int i=0;i<n;i++){
for(int site:routes[i]){
List<Integer> list=staTobus.getOrDefault(site,new ArrayList<>());
for(int j:list){
edges[i][j]=edges[j][i]=true;
}
list.add(i);
staTobus.put(site,list);
}
}
//求最短距离
int [] dis=new int [n];
//初始化数组
Arrays.fill(dis,-1);
//有多条线路都可经过起点,先将它们全部入队,
Deque<Integer> queue=new ArrayDeque<>();
for(int bus:staTobus.getOrDefault(source,new ArrayList<>())){
queue.offer(bus);
dis[bus]=1;
}
while(!queue.isEmpty()){
int x=queue.poll();
for(int i=0;i<n;i++){
if(edges[x][i]&&dis[i]==-1){
queue.offer(i);
dis[i]=dis[x]+1;
}
}
}
//找最短路径
int min=Integer.MAX_VALUE;
for(int bus:staTobus.getOrDefault(target,new ArrayList<>())){
if(dis[bus]!=-1){
min=Math.min(min,dis[bus]);
}
}
return min==Integer.MAX_VALUE?-1:min;
}
}