3112.力扣每日一题7/18 Java 迪杰斯特拉(Dijkstra)算法

举报
天天困 发表于 2024/07/26 22:33:26 2024/07/26
【摘要】 迪杰斯特拉(Dijkstra)算法迪杰斯特拉(Dijkstra)算法是一种用于求解单源最短路径问题的算法。它的基本思想是:从一个起始顶点出发,逐步向外扩展,每次选择距离起始顶点最近且未被处理过的顶点,然后更新该顶点相邻顶点的距离。以下是迪杰斯特拉算法的具体步骤:初始化:为每个顶点设置一个初始距离值。起始顶点的距离设为 0,其他顶点的距离设为无穷大。创建一个标记数组,用于标记顶点是否已处理。选...

迪杰斯特拉(Dijkstra)算法
迪杰斯特拉(Dijkstra)算法是一种用于求解单源最短路径问题的算法。
它的基本思想是:从一个起始顶点出发,逐步向外扩展,每次选择距离起始顶点最近且未被处理过的顶点,然后更新该顶点相邻顶点的距离。

以下是迪杰斯特拉算法的具体步骤:
初始化:

  1. 为每个顶点设置一个初始距离值。起始顶点的距离设为 0,其他顶点的距离设为无穷大。
    创建一个标记数组,用于标记顶点是否已处理。
    选择当前未处理且距离最小的顶点:
  2. 从所有未处理的顶点中,选择距离起始顶点最近的顶点。
    更新相邻顶点的距离:
  3. 对于所选顶点的相邻顶点,计算通过当前顶点到达相邻顶点的新距离。如果新距离小于原来的距离,则更新相邻顶点的距离。
    标记所选顶点已处理:
  4. 将所选顶点标记为已处理。
    重复步骤 2 - 4,直到所有顶点都被处理。
  5. 最终,每个顶点的距离就是从起始顶点到该顶点的最短路径长度。
    迪杰斯特拉算法的时间复杂度通常为 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;
    }
}

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。