到达目的地的方案数
难度:
标签:
题目描述
你在一个城市里,城市由 n
个路口组成,路口编号为 0
到 n - 1
,某些路口之间有 双向 道路。输入保证你可以从任意路口出发到达其他任意路口,且任意两个路口之间最多有一条路。
给你一个整数 n
和二维整数数组 roads
,其中 roads[i] = [ui, vi, timei]
表示在路口 ui
和 vi
之间有一条需要花费 timei
时间才能通过的道路。你想知道花费 最少时间 从路口 0
出发到达路口 n - 1
的方案数。
请返回花费 最少时间 到达目的地的 路径数目 。由于答案可能很大,将结果对 109 + 7
取余 后返回。
示例 1:

输入:n = 7, roads = [[0,6,7],[0,1,2],[1,2,3],[1,3,3],[6,3,3],[3,5,1],[6,5,1],[2,5,1],[0,4,5],[4,6,2]] 输出:4 解释:从路口 0 出发到路口 6 花费的最少时间是 7 分钟。 四条花费 7 分钟的路径分别为: - 0 ➝ 6 - 0 ➝ 4 ➝ 6 - 0 ➝ 1 ➝ 2 ➝ 5 ➝ 6 - 0 ➝ 1 ➝ 3 ➝ 5 ➝ 6
示例 2:
输入:n = 2, roads = [[1,0,10]] 输出:1 解释:只有一条从路口 0 到路口 1 的路,花费 10 分钟。
提示:
1 <= n <= 200
n - 1 <= roads.length <= n * (n - 1) / 2
roads[i].length == 3
0 <= ui, vi <= n - 1
1 <= timei <= 109
ui != vi
- 任意两个路口之间至多有一条路。
- 从任意路口出发,你能够到达其他任意路口。
代码结果
运行时间: 40 ms, 内存: 23.8 MB
/*
* 题目思路:
* 1. 使用Dijkstra算法计算从路口0到路口n-1的最短路径。
* 2. 使用Java Streams来初始化和处理图结构。
* 3. 初始化时,将起点0的时间设为0,路径数目设为1。
* 4. 使用优先队列维护未处理节点,根据最短时间优先处理。
* 5. 对于每个节点,更新其邻接节点的时间和路径数目。
* 6. 将最终结果取模10^9+7返回。
*/
import java.util.*;
import java.util.stream.*;
public class Solution {
private static final int MOD = 1000000007;
public int countPaths(int n, int[][] roads) {
List<List<int[]>> graph = IntStream.range(0, n)
.mapToObj(i -> new ArrayList<int[]>())
.collect(Collectors.toList());
Arrays.stream(roads).forEach(road -> {
graph.get(road[0]).add(new int[]{road[1], road[2]});
graph.get(road[1]).add(new int[]{road[0], road[2]});
});
int[] minTime = new int[n];
Arrays.fill(minTime, Integer.MAX_VALUE);
int[] count = new int[n];
minTime[0] = 0;
count[0] = 1;
PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
pq.offer(new int[]{0, 0});
while (!pq.isEmpty()) {
int[] current = pq.poll();
int u = current[0];
int time = current[1];
if (time > minTime[u]) continue;
graph.get(u).forEach(neighbor -> {
int v = neighbor[0];
int newTime = time + neighbor[1];
if (newTime < minTime[v]) {
minTime[v] = newTime;
count[v] = count[u];
pq.offer(new int[]{v, newTime});
} else if (newTime == minTime[v]) {
count[v] = (count[v] + count[u]) % MOD;
}
});
}
return count[n - 1];
}
}
解释
方法:
此题解采用了类似Dijkstra算法的变种,目的是找出从起点到终点的最短路径及其数量。首先,建立邻接表e存储图,dis数组记录从起点到每个点的最短距离,ways数组记录达到每个点的最短路径的数量。使用优先队列(最小堆)来持续处理当前未处理的最近的节点。每次从队列中取出当前距离最小的节点,更新其相邻节点的最短距离和路径数量。更新逻辑是:如果找到更短的路径,则更新最短路径和重置路径计数;如果距离相等,则累加路径数量。最终,ways数组的最后一个元素即为从起点到终点的最短路径的数量。
时间复杂度:
O((V+E) log V)
空间复杂度:
O(V+E)
代码细节讲解
🦆
在算法中`dis`数组和`ways`数组的初始化方式有何区别,以及这种初始化对算法的影响是什么?
▷🦆
为什么选择使用优先队列(最小堆)来实现这个算法,而不是使用其他数据结构如普通队列或栈?
▷🦆
在代码中,每次从优先队列中取出节点后,为什么要检查`cw <= dis[cv]`?这个条件的作用是什么?
▷🦆
当发现一条到达某个节点的等长路径(即`cw + w == dis[v]`)时,你是如何更新路径数量的,这种方法可能会引入哪些计算上的错误?
▷