方法:建图,bfs
-
建图,key为stop,value为哪些路线(index)包含这个stop。
-
起始时将「起点车站」所能进入的「路线」进行入队,每次从队列中取出「路线」时,查看该路线是否包含「终点车站」:
-
包含「终点车站」:返回进入该线路所花费的距离
-
不包含「终点车站」:遍历该路线所包含的车站,将由这些车站所能进入的路线,进行入队
-
一些细节:由于是求最短路,同一路线重复入队是没有意义的,因此将新路线入队前需要先判断是否曾经入队。
class Solution {
public int numBusesToDestination(int[][] routes, int source, int target) {
if (source == target) {
return 0;
}
// 建图,stop - routes that include this stop
Map<Integer, List<Integer>> graph = new HashMap<>();
for (int i = 0; i < routes.length; i++) {
for (int stop : routes[i]) {
List<Integer> list = graph.getOrDefault(stop, new ArrayList<>());
list.add(i); // 存route的index
graph.put(stop, list);
}
}
// 如果起点或者终点不存在
if (!graph.containsKey(source) || !graph.containsKey(target)) {
return -1;
}
// queue里存route
Queue<Integer> queue = new LinkedList<>();
// 已经访问过的route
Set<Integer> visitedRoute = new HashSet<>();
// 包含起点的route
for (int route : graph.get(source)) {
queue.add(route);
visitedRoute.add(route);
}
// 经过了几种route
int count = 0;
while (!queue.isEmpty()) {
count++;
int size = queue.size();
for (int i = 0; i < size; i++) {
int curRoute = queue.poll();
// 遍历当前route可以覆盖的stop
for (int stop : routes[curRoute]) {
// 可以到达target
if (stop == target) {
return count;
}
// 当前route覆盖不了target,遍历从当前stop出发的route
for (int nextRoute : graph.get(stop)) {
if (!visitedRoute.contains(nextRoute)) {
queue.offer(nextRoute);
visitedRoute.add(nextRoute);
}
}
}
}
}
return -1;
}
}