LeetCode 743中等图 · Dijkstra
网络延迟时间 图解题解
这道题到底在问什么
times[i]=[u,v,w] 表示信号从 u 到 v 要 w 时间。从源点 k 发出,求所有节点都收到的最短时间;有节点收不到则返回 -1。
- 输入
- n=6, k=1, times=[[1,2,2],[1,3,5],[1,4,9],[2,3,1],[2,4,4],[3,4,2],[3,5,3],[4,5,1],[4,6,6],[5,6,2],[2,5,8],[3,6,9]]
- 输出
- 8
最优解:一步一步想明白
- 3记住这句,下面每一帧都在套它。
- 4源点是节点 1:到自己的距离 dist=0,其余节点先记成 ∞(还不知道怎么到)。
- 5当前未确定的节点里,dist 最小的是节点 1(dist=0)。取出它——它的最短距离从此确定。
- 6松弛 1→2:经过 1 走,dist[1]+2=2,比原来的 ∞ 更近 → 更新 dist[2]=2。
- 7松弛 1→3:经过 1 走,dist[1]+5=5,比原来的 ∞ 更近 → 更新 dist[3]=5。
- 8松弛 1→4:经过 1 走,dist[1]+9=9,比原来的 ∞ 更近 → 更新 dist[4]=9。
- 9当前未确定的节点里,dist 最小的是节点 2(dist=2)。取出它——它的最短距离从此确定。
- 10松弛 2→3:经过 2 走,dist[2]+1=3,比原来的 5 更近 → 更新 dist[3]=3。
- 11松弛 2→4:经过 2 走,dist[2]+4=6,比原来的 9 更近 → 更新 dist[4]=6。
- 12松弛 2→5:经过 2 走,dist[2]+8=10,比原来的 ∞ 更近 → 更新 dist[5]=10。
- 13当前未确定的节点里,dist 最小的是节点 3(dist=3)。取出它——它的最短距离从此确定。
- 14松弛 3→4:经过 3 走,dist[3]+2=5,比原来的 6 更近 → 更新 dist[4]=5。
- 15松弛 3→5:经过 3 走,dist[3]+3=6,比原来的 10 更近 → 更新 dist[5]=6。
- 16松弛 3→6:经过 3 走,dist[3]+9=12,比原来的 ∞ 更近 → 更新 dist[6]=12。
- 17当前未确定的节点里,dist 最小的是节点 4(dist=5)。取出它——它的最短距离从此确定。
- 18松弛 4→5:经过 4 走是 5+1=6,不比现有的 6 近 → 不更新。
- 19松弛 4→6:经过 4 走,dist[4]+6=11,比原来的 12 更近 → 更新 dist[6]=11。
- 20当前未确定的节点里,dist 最小的是节点 5(dist=6)。取出它——它的最短距离从此确定。
- 21松弛 5→6:经过 5 走,dist[5]+2=8,比原来的 11 更近 → 更新 dist[6]=8。
- 22当前未确定的节点里,dist 最小的是节点 6(dist=8)。取出它——它的最短距离从此确定。
- 23所有节点都确定了。最大的 dist 是 8(节点最远的那个),就是信号传遍全网要的时间 → 答案 8。
⚠️ 容易写错的地方
✗ 错:把无向图处理
✓ 对:本题是有向边,只加 u→v
信号单向传,方向反了答案错
✗ 错:出堆不判过期
✓ 对:d>dist[u] 直接跳过
同一节点会被多次入堆,旧的要丢弃
✗ 错:忘了不可达返回 -1
✓ 对:有节点 dist 仍是 ∞ → -1
信号传不到所有节点时无解
完整代码(Python / C++ / Java)
Python
import heapq
def networkDelayTime(times, n, k):
g = {}
for u, v, w in times:
g.setdefault(u, []).append((v, w))
dist = {}
pq = [(0, k)]
while pq:
d, u = heapq.heappop(pq)
if u in dist: continue
dist[u] = d
for v, w in g.get(u, []):
if v not in dist:
heapq.heappush(pq, (d + w, v))
return max(dist.values()) if len(dist) == n else -1C++
#include <vector>
#include <queue>
using namespace std;
int networkDelayTime(vector<vector<int>>& times, int n, int k){
vector<vector<pair<int,int>>> g(n + 1);
for(auto& t : times) g[t[0]].push_back({t[1], t[2]});
vector<int> dist(n + 1, INT_MAX); dist[k] = 0;
priority_queue<pair<int,int>, vector<pair<int,int>>, greater<>> pq;
pq.push({0, k});
while(!pq.empty()){
auto [d, u] = pq.top(); pq.pop();
if(d > dist[u]) continue;
for(auto& [v, w] : g[u])
if(d + w < dist[v]){ dist[v] = d + w; pq.push({dist[v], v}); }
}
int ans = 0;
for(int i = 1; i <= n; i++){ if(dist[i] == INT_MAX) return -1; ans = max(ans, dist[i]); }
return ans;
}Java
import java.util.*;
class Solution {
public int networkDelayTime(int[][] times, int n, int k) {
List<int[]>[] g = new List[n + 1];
for (int i = 1; i <= n; i++) g[i] = new ArrayList<>();
for (int[] t : times) g[t[0]].add(new int[]{t[1], t[2]});
int[] dist = new int[n + 1];
Arrays.fill(dist, Integer.MAX_VALUE);
dist[k] = 0;
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
pq.offer(new int[]{0, k});
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int d = cur[0], u = cur[1];
if (d > dist[u]) continue;
for (int[] e : g[u]) {
int v = e[0], w = e[1];
if (d + w < dist[v]) {
dist[v] = d + w;
pq.offer(new int[]{dist[v], v});
}
}
}
int ans = 0;
for (int i = 1; i <= n; i++) {
if (dist[i] == Integer.MAX_VALUE) return -1;
ans = Math.max(ans, dist[i]);
}
return ans;
}
}复杂度
时间
O(E log V)
每条边最多入堆一次,堆操作 log V
空间
O(V + E)
邻接表 + dist + 堆
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 网络延迟时间 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
边权有负数还能用 Dijkstra 吗?+
不能。负权会破坏「取出即确定」的前提,要用 Bellman-Ford 或 SPFA。
为什么用优先队列而不是每次线性扫最小?+
线性扫是 O(V²);堆把取最小降到 O(log V),稀疏图整体 O(E log V) 更优。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 网络延迟时间 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。