找到最短路径的 K 次跨越
难度:
标签:
题目描述
代码结果
运行时间: 848 ms, 内存: 21.0 MB
/**
* LeetCode 2714: 找到最短路径的 K 次跨越
*
* 题目思路:
* 1. 使用广度优先搜索(BFS)算法,适用于寻找无权图中的最短路径。
* 2. 利用一个队列来进行层次遍历,每层代表跨越次数。
* 3. 使用一个三维数组来记录节点是否访问过以及访问时的最小跨越次数。
* 4. 对于每个节点,遍历其所有邻居节点,进行状态转移并记录最小跨越次数。
* 5. 当找到目标节点时,返回其最小跨越次数。
*/
import java.util.*;
import java.util.stream.IntStream;
public class SolutionStream {
public int shortestPathWithKCrossings(int[][] graph, int start, int end, int k) {
int n = graph.length;
int[][][] visited = new int[n][n][k + 1];
Queue<int[]> queue = new LinkedList<>();
queue.add(new int[]{start, 0, 0}); // {当前节点, 当前跨越次数, 当前路径长度}
while (!queue.isEmpty()) {
int[] curr = queue.poll();
int node = curr[0];
int crossings = curr[1];
int length = curr[2];
if (node == end) return length;
if (crossings > k) continue;
IntStream.range(0, n)
.filter(next -> graph[node][next] == 1 && visited[node][next][crossings + 1] == 0)
.forEach(next -> {
visited[node][next][crossings + 1] = 1;
queue.add(new int[]{next, crossings + 1, length + 1});
});
}
return -1; // 如果无法到达目标节点
}
}
解释
方法:
该题解采用了优先队列(最小堆)结合动态规划的方法在图中寻找从起点到终点的最短路径,同时限制路径中的跳数不超过K次。首先构建每个节点的邻接表来表示图。定义一个二维数组 dist,其中 dist[i][j] 表示从起点 s 到节点 i 使用 j 次跳的最短距离。初始化所有距离为无穷大,只有起点 s 在跳数为0的情况下距离为0。使用优先队列来存储当前的节点、距离及已经使用的跳数。每次从队列中取出距离最小的节点进行扩展,更新通过该节点可能达到的邻接节点的最短距离。如果通过当前节点直接到达邻接节点的距离小于已记录的距离,或者通过当前节点跳转到邻接节点(增加一次跳数)的情况下距离更短,则更新相应的距离并将该状态加入队列中。最后,从 dist 数组中的终点 d 相关的所有跳数中选取最小的距离返回。
时间复杂度:
O(n*k*log(n*k))
空间复杂度:
O(E + n*k)
代码细节讲解
🦆
为什么在初始化`dist`数组时,距离不是被设置为无穷大而是选择性地将起点距离设置为0?这对算法的执行有什么影响?
▷🦆
优先队列中的元素是如何保证按照距离进行排序的?是否需要在每次插入时进行比较或存在其他内置机制来保持队列的顺序?
▷🦆
在扩展节点时,你提到了`如果当前节点的距离已经不是最小,跳过`,这种情况是如何发生的?为什么会有不是最小的距离的节点出现在优先队列中?
▷