743. 网络延迟时间


n 个网络节点,标记为 1n

给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。

现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1

示例 1:

1
2
输入:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
输出:2

示例 2:

1
2
输入:times = [[1,2,1]], n = 2, k = 1
输出:1

示例 3:

1
2
输入:times = [[1,2,1]], n = 2, k = 2
输出:-1

提示:

  • 1 <= k <= n <= 100
  • 1 <= times.length <= 6000
  • times[i].length == 3
  • 1 <= ui, vi <= n
  • ui != vi
  • 0 <= wi <= 100
  • 所有 (ui, vi) 对都 互不相同(即,不含重复边)

SPFA算法(链式向前星建图)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
class SPFA {
final int INF = Integer.MAX_VALUE;
// dists->distances, counts->记录顶点入队次数,用于负圈检测, inQueue->是否在当前队列
int dists[], counts[], inQueue[];
// n->E, m->V, s->start, [heads, nexts, tos, weights]->链式向前星
int n, m, s, heads[], nexts[], tos[], weights[];

public SPFA(int n, int s, int edges[][]) {
this.n = n;
this.s = s;
m = edges.length;
int edgeNum = 1; // range: [2, 2*m+1]
dists = new int[n+1];
counts = new int[n+1];
inQueue = new int[n+1];
heads = new int[n + 1];
tos = new int[2 * m + 2];
nexts = new int[2 * m + 2];
weights = new int[2 * m + 2];
for (int[] edge : edges) { // 链式向前星建图
int u = edge[0], v = edge[1], w = edge[2];
// 添加边 (u, v)
++edgeNum;
nexts[edgeNum] = heads[u];
heads[u] = edgeNum;
tos[edgeNum] = v;
weights[edgeNum] = w;
// 添加反向边 (v, u)
// ++edgeNum;
// nexts[edgeNum] = heads[v];
// heads[v] = edgeNum;
// tos[edgeNum] = u;
// weights[edgeNum] = 0;
}
}

public boolean bfs() {
Arrays.fill(dists, INF);
Deque<Integer> q = new LinkedList<>();
q.offer(s);
dists[s] = 0;
while (!q.isEmpty()) {
int p = q.poll();
inQueue[p] = 0;
for (int eg = heads[p]; eg != 0; eg = nexts[eg]) {
int to = tos[eg];
if (dists[to] > dists[p] + weights[eg]) {
dists[to] = dists[p] + weights[eg];
if (inQueue[to] == 0) {
inQueue[to] = 1;
q.offer(to);
if (counts[to] > n - 1) { // 负圈检测
System.out.println("Negative Cycle Found!");
return false;
}
else {
counts[to] += 1;
}
}
}
}
}
return true;
}
}

class Solution {
public int networkDelayTime(int[][] times, int n, int k) {
int res = 0;
SPFA spfa = new SPFA(n, k, times);
spfa.bfs();
for (int i = 1; i <= n; i++) { // 找最短路长度最大者
int dist = spfa.dists[i];
if (dist == spfa.INF) return -1; // 存在距离未更新的顶点
if (dist > res) res = dist;
}
return res;
}
}

SPFA算法(邻接表建图)

一些细节也不一样

  • 这里数组大小是n,所以index要-1
  • 这里直接用队列判定是否在队列中,而不是定义一个数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class SPFA {
final int INF = Integer.MAX_VALUE;
// n->num, s->start, dists->distances, counts->记录顶点入队次数,用于负圈检测
int n, s, dists[], counts[];
List<int[]> g [];
public SPFA(int n, int s, List<int[]> g[]) {
this.n = n; this.s = s; this.g = g;
this.dists = new int[n]; this.counts = new int[n];
}
public boolean bfs() {
Arrays.fill(dists, INF);
dists[s - 1] = 0;
Deque<Integer> q = new LinkedList<>();
q.add(s - 1);
while (!q.isEmpty()) {
int u = q.poll();
for (int vw[] : g[u]) {
int v = vw[0], w = vw[1];
if (dists[u] + w < dists[v]) { // 松弛u的邻接顶点
dists[v] = dists[u] + w;
if (!q.contains(v)) { // 入队的前提是此时v不在q中,否则程序虽正确,但复杂度将不再是O(|V||E|)
q.add(v);
if (counts[v] > n - 1) { // 负圈检测
System.out.println("Negative Cycle Found!");
return false;
} else {
counts[v] += 1;
}
}
}
}
}
return true;
}
}
class Solution {
public int networkDelayTime(int[][] times, int n, int k) {
List<int[]> g[] = new ArrayList[n];
Arrays.setAll(g, i -> new ArrayList<>());
for(int[] e : times) {
int u = e[0]-1, v = e[1]-1, w = e[2];
g[u].add(new int[]{v, w});
}
int res = 0;
SPFA spfa = new SPFA(n, k, g);
spfa.bfs();
for(int dist : spfa.dists){ // 找最短路长度最大者
if(dist == spfa.INF) return -1; // 存在距离未更新的顶点
if(dist > res) res = dist;
}
return res;
}
}

Dijkstra算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public int networkDelayTime(int[][] times, int n, int k) {
int g[][] = new int[n][n];
for (int i = 0; i < n; i++) Arrays.fill(g[i], -1);
for (int[] time : times) {
int cur = time[0] - 1, next = time[1] - 1, len = time[2];
g[cur][next] = len;
}
int dis[] = new int[n];
Arrays.fill(dis, Integer.MAX_VALUE);
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]);
dis[k - 1] = 0;
pq.offer(new int[]{k-1, 0});
while (!pq.isEmpty()) {
int poll[] = pq.poll(), cur = poll[0], d = poll[1];
for (int i = 0; i < n; i++) {
if (g[cur][i] == -1) continue;
if (d + g[cur][i] < dis[i]) {
dis[i] = d + g[cur][i];
pq.offer(new int[]{i, dis[i]});
}
}
}
int res = Arrays.stream(dis).max().getAsInt();
return res == Integer.MAX_VALUE ? -1 : res;
}
}