3112.力扣每日一题7/18 Java 迪杰斯特拉(Dijkstra)算法
迪杰斯特拉(Dijkstra)算法
迪杰斯特拉(Dijkstra)算法是一种用于求解单源最短路径问题的算法。
它的基本思想是:从一个起始顶点出发,逐步向外扩展,每次选择距离起始顶点最近且未被处理过的顶点,然后更新该顶点相邻顶点的距离。
以下是迪杰斯特拉算法的具体步骤:
初始化:
- 为每个顶点设置一个初始距离值。起始顶点的距离设为 0,其他顶点的距离设为无穷大。
创建一个标记数组,用于标记顶点是否已处理。
选择当前未处理且距离最小的顶点: - 从所有未处理的顶点中,选择距离起始顶点最近的顶点。
更新相邻顶点的距离: - 对于所选顶点的相邻顶点,计算通过当前顶点到达相邻顶点的新距离。如果新距离小于原来的距离,则更新相邻顶点的距离。
标记所选顶点已处理: - 将所选顶点标记为已处理。
重复步骤 2 - 4,直到所有顶点都被处理。 - 最终,每个顶点的距离就是从起始顶点到该顶点的最短路径长度。
迪杰斯特拉算法的时间复杂度通常为 O(N²),其中N是顶点的数量。如果使用二叉堆如果使用二堆(或斐波那契堆)来优化选择最小距离顶点的操作,时间复杂度可以优化到O((N+M)logN),其中M是边的数量
解题思路
使用迪杰斯特拉(Dijkstra)算法的思想,通过优先级队列来找到从节点 0 到其他节点的最短时间。同时考虑每个节点的消失时间,如果在节点消失之前无法到达,则标记为不可达(-1)。
解题过程
首先构建图的邻接表表示。
初始化每个节点的最少到达时间为 -1,节点 0 的到达时间为 0 ,并创建优先级队列。
当优先级队列不为空时,取出队首元素。
对于取出节点的每个邻居节点,计算新的到达时间。如果新的到达时间小于邻居节点的消失时间,并且比之前记录的到达时间更短,就更新邻居节点的到达时间,并将其加入优先级队列。
时间复杂度
主要的时间消耗在于优先级队列的操作和对图的遍历。在最坏情况下,对于一个包含 n 个节点和 m 条边的图,时间复杂度为 O((n + m) log n) 。但在这个问题中,由于每个节点最多被处理一次,并且边也只会被访问有限次,所以更接近 O(n log n)
空间复杂度
使用了邻接表来存储图,空间复杂度为 O(n + m) ,还使用了一个长度为 n 的数组来存储每个节点的最少到达时间和一个优先级队列,空间复杂度主要取决于节点数量 n 和边数量 m ,大致为 O(n + m) 。
代码如下:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
class Solution {
public int[] minimumTime(int numNodes, int[][] edgeInfos, int[] vanishTimings) {
// 使用邻接表表示图
ArrayList<int[]>[] graph = new ArrayList[numNodes];
Arrays.setAll(graph, i -> new ArrayList<>());
// 构建图
for (int[] edge : edgeInfos) {
int nodeA = edge[0];
int nodeB = edge[1];
int weight = edge[2];
graph[nodeA].add(new int[]{nodeB, weight});
graph[nodeB].add(new int[]{nodeA, weight});
}
// 存储每个节点的最少到达时间
int[] minReachTimes = new int[numNodes];
Arrays.fill(minReachTimes, -1);
minReachTimes[0] = 0;
// 优先级队列,按到达时间排序
PriorityQueue<int[]> priorityQueue = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
priorityQueue.offer(new int[]{0, 0});
while (!priorityQueue.isEmpty()) {
int[] current = priorityQueue.poll();
int currentReachTime = current[0];
int currentNode = current[1];
// 如果当前节点之前已经有更短的到达时间,跳过
if (currentReachTime > minReachTimes[currentNode]) {
continue;
}
for (int[] neighbor : graph[currentNode]) {
int neighborNode = neighbor[0];
int newReachTime = currentReachTime + neighbor[1];
// 如果新的到达时间小于邻居节点消失时间,并且比之前记录的到达时间更短
if (newReachTime < vanishTimings[neighborNode] && (minReachTimes[neighborNode] < 0 || newReachTime < minReachTimes[neighborNode])) {
minReachTimes[neighborNode] = newReachTime;
priorityQueue.offer(new int[]{newReachTime, neighborNode});
}
}
}
return minReachTimes;
}
}
- 点赞
- 收藏
- 关注作者
评论(0)