您现在的位置是:首页 >技术交流 >leetcode-743. 网络延迟时间网站首页技术交流

leetcode-743. 网络延迟时间

请叫我Oscar 2024-06-17 11:27:54
简介leetcode-743. 网络延迟时间

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.思路分析:

一道Dijkstra模板题
推荐Dijkstra算法讲解教程

Dijkstra(有向图某点到其他所有点的最短路径问题)

Dijkstra算法的基本思想是贪心策略,每次从未确定最短路径的顶点中选择距离源点最近的一个,然后以该顶点为中介,更新其他顶点到源点的距离。这个过程重复执行,直到所有顶点都确定了最短路径。

Dijkstra算法的时间复杂度取决于使用的数据结构,如果使用数组或链表存储顶点集合,时间复杂度为O(n^2),如果使用优先队列或二叉堆存储顶点集合,时间复杂度为O((m+n)logn),其中n是顶点数,m是边数。

Dijkstra算法的一个重要条件是图中不能有负权边,否则算法可能无法得到正确的结果

本题思路

创建一个具有双向链表的节点类Node,

class Node{
	int key;
    int value;
	Node prev;
	Node next;
	public Node(int value){
		this.value = value;	
	}
}

创建一个双向链表类DoubleLinkList,实现头尾虚拟节点,并且初始化他们的相互连接。
并且实现删除头结点,插入节点,插入尾节点功能。
再借助DoubleLinkList实现题目中的LRUCache类。

2. 算法实现

static int[][] map ;
static int INF = Integer.MAX_VALUE;
static int[] dis;
static int[] flag;
public static int networkDelayTime(int[][] times, int n, int k) {
    //n是点的数量,k是起点
    map = new int[n][n];//点与点之间的边连接情况
    dis = new int[n];//最短路径数组
    flag = new int[n];//已访问过的数组
    flag[k - 1] = 1;
    for(int i = 0;i < n;i++){//初始化图,各个点之间都不连通
        for(int j = 0;j < n;j++){
            map[i][j] = INF;
        }
    }
    for(int i = 0;i < times.length;i++){//将题目中的边初始化到图中
        map[times[i][0] - 1][times[i][1] - 1] = times[i][2];
    }
    for(int i = 0;i < n;i++){//将起始点到其他各个点的距离初始化到最短路径数组中
        dis[i] = map[k - 1][i];
    }
    dis[k - 1] = 0;//自己到自己初始化为0
    //Dijikstra
    int loop = 0;
    while(loop < n - 1){//循环总点数-1次,访问其他点到源点的最短距离
        int min = INF;
        int minIndex = -1;
        for(int i = 0;i < n;i++){//找到当前还未访问的点中距离源地最近的点
            if(min > dis[i] && flag[i] == 0){
                min = dis[i];
                minIndex = i;
            }
        }
        if(minIndex != -1){//当前距离源点最近的点标记为访问过
            flag[minIndex] = 1;
        }else{//当前未访问的点到源点都不可达
            return -1;
        }
        for(int i = 0;i < n;i++){//以当前到源点最近的点为中间点
            if(map[minIndex][i] != INF && flag[i] != 1){//遍历的点未被访问过,并且当前中间点到该点可达
                if(dis[minIndex] + map[minIndex][i] < dis[i]){
                    dis[i] = dis[minIndex] + map[minIndex][i];
                }
            }
        }
        loop++;
    }
    int max = Integer.MIN_VALUE;
    for(int val : dis){
        if(val == INF){
            return -1;
        }else if(max < val){
            max = val;
        }
    }
    return max;
}

3. 算法坑点

  1. 注意笨题解采用邻接表实现图,题目给出的是从1开始的序号,记得把序号-1,再对map中对应下标的值进行操作。(因为map是二维数组,下标默认从0开始)
  2. 以下这段代码是找当前还未访问过的点钟距离源点最近的点,
int min = INF;
int minIndex = -1;
for(int i = 0;i < n;i++){//找到当前还未访问的点中距离源地最近的点
    if(min > dis[i] && flag[i] == 0){
        min = dis[i];
        minIndex = i;
    }
}
flag[minIndex] = 1;//当前距离源点最近的点标记为访问过

但是min初始化为INF,有可能有个潜在的情况,当前未访问的所有的点到源点都是不可达,即距离为INF,此时在flag[minIndex] = 1赋值前做一个判断。

if(minIndex != -1){//当前距离源点最近的点标记为访问过
    flag[minIndex] = 1;
}else{//当前未访问的点到源点都不可达
    return -1;
}
  1. 在比较源点到中间点最短距离+中间点到剩余未访问的点距离源点到中间点最短距离时,注意其他点应该是未被访问过的。
 if(flag[i] != 1 && map[minIndex][i] != INF)//flag[i] != 1 未被访问过的,并且中间点到未访问点之间可达

为什么其他点应该是未被访问过的,因为访问过的点已经找到最短路径了。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。