743. 网络延迟时间
我的思路
- 显然,这是一道求 单源最短路最长 的题目。
- 并且这是一个正权图( 0 ≤ w i ≤ 100 0 \le w_i \le 100 0≤wi≤100)。
- 因此,
dijkstra
+priority_queue
是解题之道。- 如果对最短路算法存疑,可以参考博客:最短路
- 不妨使用 链式前向星 存储图。
- 如果对这种存储方式有问题可以参考博客:图的存储
根据上面的思路可以写出AC代码:
class Solution {
public:
vector<int> to, weight, next, head;
int V, E;
int networkDelayTime(vector<vector<int>>& times, int n, int k) {
int V = n; // 顶点个数
int E = times.size(); // 边数
head.resize(V+1, -1); // head调整大小
for (auto item : times){ // 建立图
addEdge(item[0], item[1], item[2]);
}
const int INF= 0x3f3f3f3f; // 无穷大
int S = k; // 设置起始节点
vector<int> dis(V+1, INF); // 记录最短路长度的数组
dis[S] = 0; // S到自己的距离是0
using Pair = pair<int, int>; // 方便书写
priority_queue<Pair, vector<Pair>, greater<Pair>> pque; // 小根堆
pque.push(Pair(0, S)); // S入堆
while (!pque.empty()){
int u = pque.top().second;
pque.pop();
for (int e = head[u]; ~e; e = next[e]){ // 对每一条出边进行松弛操作
int v = to[e];
int w = weight[e];
if (dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
pque.push(Pair(dis[v], v));
}
}
}
int ret = *max_element(dis.begin()+1, dis.end()); // 获取最短路最长
if (ret == INF){
return -1;
}else{
return ret;
}
}
void addEdge(int u, int v, int w){
next.push_back(head[u]);
to.push_back(v);
weight.push_back(w);
head[u] = next.size() - 1;
}
};
执行用时:148 ms, 在所有 C++ 提交中击败了60.96%的用户
内存消耗:42.9 MB, 在所有 C++ 提交中击败了9.40%的用户
- 复杂度分析:
- 时间复杂度:
O
(
E
⋅
l
o
g
E
)
O(E\cdot logE)
O(E⋅logE),其中E是图的边数,即
E=times.size()
;这一复杂度是优先队列优化dijkstra算法的时间复杂度。 - 空间复杂度:
O
(
m
a
x
(
V
,
E
)
)
O(max(V, E))
O(max(V,E)),其中V是顶点个数,即
V=n
.开辟了五个V大小的数组,优先队列的大小是E。
- 时间复杂度:
O
(
E
⋅
l
o
g
E
)
O(E\cdot logE)
O(E⋅logE),其中E是图的边数,即
实现2
上面代码使用的是链式前向星存储图。如果对这种方式存储有疑问的话。下面提供一种简单的使用Vector存储图的方式。
使用vector存储图的AC实现(注释略):
class Solution {
public:
int V, E;
const int MAX_V = 101;
int networkDelayTime(vector<vector<int>>& times, int n, int k) {
V = n;
E = times.size();
using Pair = pair<int, int>;
vector<Pair> T[MAX_V];
// 或者使用下面这种方式,或许还能省一些空间(笑):
/**
vector<vector<Pair>> T;
T.resize(V+1);
**/
for (auto elem : times){
T[elem[0]].emplace_back(Pair(elem[1], elem[2]));
}
const int INF = 0x3f3f3f3f;
int S = k;
vector<int> dis(V + 1, INF);
dis[S] = 0;
priority_queue<Pair, vector<Pair>, greater<Pair>> pque;
pque.push(Pair(0, S));
while (!pque.empty()){
int u = pque.top().second;
pque.pop();
for (auto elem : T[u]){
if (dis[elem.first] > dis[u] + elem.second){
dis[elem.first] = dis[u] + elem.second;
pque.push(Pair(dis[elem.first], elem.first));
}
}
}
int ret = *max_element(dis.begin()+1, dis.end());
if (ret == INF){
return -1;
}
return ret;
}
};
执行用时:200 ms, 在所有 C++ 提交中击败了30.37%的用户
内存消耗:42.5 MB, 在所有 C++ 提交中击败了12.44%的用户
- 这种存图方式类似于使用vector实现的邻接表。
pair<int, int>
中的第一个int
的含义是边 ( u , v ) (u,v) (u,v) 中的 v v v ,第二个int
的含义是权重。- 详细可以访问博客:图的存储