Leetcode 743 Network Delay Time,单源最短路径问题的解法
🎈思路
Leetcode 743 Network Delay Time,在一个网络节点组成的有n
个点的加权有向图中,返回从给定某一节点k
出发发送信号,所有节点都能收到信号的耗时,有无法到达的节点则返回 -1。
这里要求我们找到从k
点出发,到其他所有点的最短路径的最大值,是一个单源的最短路问题。解决单源的最短路问题,如果无负权边,通常采用 Dijkstra 算法,如果有负向边,就采用 Bellman-Ford 算法。
🎆Dijkstra 算法
Dijkstra 算法不断遍历离起始点最近且未访问过的节点,对每个未访问过的节点,遍历已访问过的节点以获取该节点距离起始点的最短距离。
我们需要求出节点k
到其余所有点的最短路,其中的最大值就是答案。若存在从k
出发无法到达的点,则返回 −1。
值得注意的是,最后返回最大值无需搜索整个距离数组。我们遍历节点是从近到远的,因此,最后一个节点肯定是离起始点最远的,因此,只需记录最近一次遍历节点的距离,到最后作为结果返回。
rust- impl Solution {
- pub fn network_delay_time(times: Vec<Vec<i32>>, n: i32, k: i32) -> i32 {
- const MAX: i32 = 114514; // 这题节点权重最大 100,随便定个数当 inf 吧
- let n_usize = n as usize;
- // 构造邻接矩阵
- let mut adjacency_map = vec![vec![MAX; n_usize]; n_usize];
- for t in × {
- adjacency_map[t[0] as usize - 1][t[1] as usize - 1] = t[2];
- }
- let basic_row = k as usize - 1;
- // 直接在第 k - 1 行上更新状态
- adjacency_map[basic_row][basic_row] = 0;
- let mut visit = vec![false; n_usize];
- let mut last_dist = 0; // 记录最近遍历的节点的距离
- loop {
- let mut idx = n_usize;
- for (i, &v) in visit.iter().enumerate() {
- if !v && (idx == n_usize || (adjacency_map[basic_row][i] < adjacency_map[basic_row][idx])) {
- idx = i;
- }
- }
- if idx == n_usize {
- return last_dist;
- }
- if adjacency_map[basic_row][idx] >= MAX {
- return -1;
- }
- visit[idx] = true;
- for i in 0..n_usize {
- let res = adjacency_map[basic_row][i].min(adjacency_map[basic_row][idx] + adjacency_map[idx][i]);
- adjacency_map[basic_row][i] = res;
- }
- last_dist = adjacency_map[basic_row][idx];
- }
- }
- }
可以看到,需要遍历所有节点,外层循环时间复杂度 ,寻找最近节点和更新节点距离需要时间复杂度 ,时间复杂度 。需要构造邻接矩阵,空间复杂度
🎇堆优化的 Dijkstra 算法
当图是稀疏图时,使用堆优化的 Dijkstra 算法更快,时间复杂度 ,空间复杂度 , 是边的数量。这里用堆排序代替线性地查找最近节点。
稀疏图就是…边比较少的图,具体怎么定义看使用场景,上面写的的朴素的 Dijkstra 时间复杂度大概是 ,堆优化的时间复杂度是 。就这里而言所以稀疏图和稠密图的界限大概在 处,这也不怎么准确,毕竟时间复杂度是省略了低阶项和系数的结果…
rust- use std::collections::BinaryHeap;
- impl Solution {
- pub fn network_delay_time(times: Vec<Vec<i32>>, n: i32, k: i32) -> i32 {
- const MAX: i32 = 114514;
- let n_usize = n as usize;
- let mut adjacency_map = vec![vec![]; n_usize];
- for t in × {
- adjacency_map[t[0] as usize - 1].push((t[1] as usize - 1, t[2]));
- }
- let mut dist = vec![MAX; n_usize];
- let basic_row = k as usize - 1;
- dist[basic_row] = 0;
- let mut heap = BinaryHeap::new(); // 建立二叉堆
- heap.push((0, basic_row));
- let mut last_dist = 0; // 类似地,记录上次的节距离
- let mut node_count = 0; // 记录遍历节点数,不足 n 个就说明有不可到达的点,返回 -1
- while let Some((dist_min, x)) = heap.pop() {
- if -dist_min > dist[x] {
- continue;
- }
- node_count += 1;
- let len = adjacency_map[x].len();
- for i in 0..len {
- let (y, weight) = adjacency_map[x][i];
- let new_dist = -dist_min + weight;
- if new_dist < dist[y] {
- dist[y] = new_dist;
- heap.push((-new_dist, y));
- }
- }
- last_dist = dist[x];
- }
- if (node_count < n) {
- return -1;
- }
- return last_dist;
- }
- }
✨Bellman-Ford 算法
Bellman-Ford 算法主要用于有负权的图,它的思想是对所有的边进行 轮松弛操作,因为在一个含有 个顶点的图中,任意两点之间的最短路径最多包含 边。时间复杂度 ,空间复杂度 , 是边数。
rust- impl Solution {
- pub fn network_delay_time(times: Vec<Vec<i32>>, n: i32, k: i32) -> i32 {
- let MAX = 114514;
- let mut dis = vec![MAX; n as usize];
- dis[(k - 1) as usize] = 0;
- let edge_count = times.len();
- let (mut to, mut from, mut weight) = (vec![0; edge_count], vec![0; edge_count], vec![0; edge_count]);
- for i in 0..edge_count {
- let edge = ×[i as usize];
- to[i as usize] = edge[1] - 1;
- from[i as usize] = edge[0] - 1;
- weight[i as usize] = edge[2];
- }
- for k in 0..n - 1 {
- let mut changed = false;
- for i in 0..edge_count {
- let rest = dis[from[i as usize] as usize] + weight[i as usize];
- if (dis[to[i as usize] as usize] > rest) {
- dis[to[i as usize] as usize] = rest;
- changed = true;
- }
- }
- if !changed {
- break;
- }
- }
- let mut ans = 0;
- for i in 0..n {
- ans = if dis[i as usize] < ans { ans } else { dis[i as usize] };
- }
- return if ans < MAX { ans } else { -1 };
- }
- }
🎁结语
解决单源的最短路问题,如果无负权边,通常采用 Dijkstra 算法,对于稀疏图,可以进行堆优化;如果有负向边,就采用 Bellman-Ford 算法。
参考
https://leetcode.cn/problems/network-delay-time/solutions/2668220/liang-chong-dijkstra-xie-fa-fu-ti-dan-py-ooe8/
https://leetcode.cn/problems/network-delay-time/solutions/2999961/tu-lun-bfs-liang-chong-dijkstra-floyd-be-cfdv/