有 n 个城市通过一些航班连接。给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,以价格 pricei 抵达 toi。
现在给定所有的城市和航班,以及出发城市 src 和目的地 dst,你的任务是找到出一条最多经过 k 站中转的路线,使得从 src 到 dst 的价格最便宜,并返回该价格。如果不存在这样的路线,则输出 -1。
import java.util.*;
class Solution {
public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
// 1. 建立邻接表 (有向图),存储每个城市的出发航班
Map> graph = new HashMap<>();
for (int[] flight : flights) {
// flight[0] 是出发城市,flight[1] 是目的地,flight[2] 是票价
graph.computeIfAbsent(flight[0], x -> new ArrayList<>()).add(new int[]{flight[1], flight[2]});
}
// 2. BFS 队列存储 [当前城市, 当前累计价格, 剩余中转次数]
Queue queue = new LinkedList<>();
queue.offer(new int[]{src, 0, k + 1});
// 3. 记录到达每个城市的最小花费,初始化为最大值,防止不必要的重复遍历
int[] minCost = new int[n];
Arrays.fill(minCost, Integer.MAX_VALUE);
minCost[src] = 0;
// 4. 开始 BFS 遍历
while (!queue.isEmpty()) {
int[] node = queue.poll();
int city = node[0]; // 当前所在城市
int cost = node[1]; // 当前累计的票价
int stops = node[2]; // 剩余可中转次数
if (stops > 0) { // 只有还有中转次数,才能继续前进
for (int[] next : graph.getOrDefault(city, new ArrayList<>())) {
int nextCity = next[0]; // 下一站城市
int price = next[1]; // 从当前城市到下一站的票价
// 只有找到更便宜的价格才更新,并且入队
if (cost + price < minCost[nextCity]) {
minCost[nextCity] = cost + price;
queue.offer(new int[]{nextCity, cost + price, stops - 1});
}
}
}
}
// 5. 返回最小花费,如果仍为 Integer.MAX_VALUE 说明无法到达
return minCost[dst] == Integer.MAX_VALUE ? -1 : minCost[dst];
}
}
我们用 Map
来存储航班信息,使得 graph.get(i)
代表城市 i
出发的所有航班列表。
示例输入:
flights = [
[0, 1, 100],
[1, 2, 100],
[2, 0, 100],
[1, 3, 600],
[2, 3, 200]
]
存入 graph
后的结构:
{
0 -> [[1, 100]],
1 -> [[2, 100], [3, 600]],
2 -> [[0, 100], [3, 200]]
}
我们使用 BFS 进行搜索,每个队列元素存储 [当前城市, 当前累计价格, 剩余中转次数]
。 初始队列:
queue = [[src, 0, k + 1]]
minCost[i]
记录从 src
出发到 i
的最小花费,初始时设为 Integer.MAX_VALUE
。
Arrays.fill(minCost, Integer.MAX_VALUE);
minCost[src] = 0;
每次从队列取出一个城市 city
,如果 stops > 0
,则遍历 city
可达的所有 nextCity
。
如果 cost + price < minCost[nextCity]
,就更新 minCost[nextCity]
并入队。
示例流程(假设 k = 1):
1. 初始:queue = [[0, 0, 2]]
2. 取出 [0, 0, 2],发现 0 -> 1 (100)
-> queue = [[1, 100, 1]]
3. 取出 [1, 100, 1],发现 1 -> 2 (100) 和 1 -> 3 (600)
-> queue = [[2, 200, 0], [3, 700, 0]]
4. 取出 [2, 200, 0],但 stops = 0,不再继续。
5. 取出 [3, 700, 0],但 stops = 0,不再继续。
最终 minCost[dst]
存储了 src -> dst
的最小票价。
这类题目通常具备以下特点:
Map> graph = new HashMap<>();
graph.put(from, [to, price])
Queue queue = new LinkedList<>();
queue.offer(new int[]{src, 0, k + 1});
if (cost + price < minCost[nextCity]) {
minCost[nextCity] = cost + price;
queue.offer(new int[]{nextCity, cost + price, stops - 1});
}
if (stops > 0) { // 只有还可以中转才继续 }
✅ 总结 ✔ 这题可以作为 BFS + 限制步数最短路径的模板。 ✔ 适用于“有限步数内的最短路径”问题。 ✔ 熟练掌握后,可以解决一类类似的题目!