LeetCode 题解工作台
设计可以求最短路径的图类
给你一个有 n 个节点的 有向带权 图,节点编号为 0 到 n - 1 。图中的初始边用数组 edges 表示,其中 edges[i] = [from i , to i , edgeCost i ] 表示从 from i 到 to i 有一条代价为 edgeCost i 的边。 请你实现一个 Gra…
4
题型
6
代码语言
3
相关题
当前训练重点
困难 · 堆
答案摘要
在初始化函数中,我们先用邻接矩阵 存储图的边权,其中 表示从节点 到节点 的边权,如果 和 之间没有边,则 的值为 。 在 `addEdge` 函数中,我们更新 的值为 。
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 堆 题型思路
题目描述
给你一个有 n 个节点的 有向带权 图,节点编号为 0 到 n - 1 。图中的初始边用数组 edges 表示,其中 edges[i] = [fromi, toi, edgeCosti] 表示从 fromi 到 toi 有一条代价为 edgeCosti 的边。
请你实现一个 Graph 类:
Graph(int n, int[][] edges)初始化图有n个节点,并输入初始边。addEdge(int[] edge)向边集中添加一条边,其中edge = [from, to, edgeCost]。数据保证添加这条边之前对应的两个节点之间没有有向边。int shortestPath(int node1, int node2)返回从节点node1到node2的路径 最小 代价。如果路径不存在,返回-1。一条路径的代价是路径中所有边代价之和。
示例 1:

输入: ["Graph", "shortestPath", "shortestPath", "addEdge", "shortestPath"] [[4, [[0, 2, 5], [0, 1, 2], [1, 2, 1], [3, 0, 3]]], [3, 2], [0, 3], [[1, 3, 4]], [0, 3]] 输出: [null, 6, -1, null, 6] 解释: Graph g = new Graph(4, [[0, 2, 5], [0, 1, 2], [1, 2, 1], [3, 0, 3]]); g.shortestPath(3, 2); // 返回 6 。从 3 到 2 的最短路径如第一幅图所示:3 -> 0 -> 1 -> 2 ,总代价为 3 + 2 + 1 = 6 。 g.shortestPath(0, 3); // 返回 -1 。没有从 0 到 3 的路径。 g.addEdge([1, 3, 4]); // 添加一条节点 1 到节点 3 的边,得到第二幅图。 g.shortestPath(0, 3); // 返回 6 。从 0 到 3 的最短路径为 0 -> 1 -> 3 ,总代价为 2 + 4 = 6 。
提示:
1 <= n <= 1000 <= edges.length <= n * (n - 1)edges[i].length == edge.length == 30 <= fromi, toi, from, to, node1, node2 <= n - 11 <= edgeCosti, edgeCost <= 106- 图中任何时候都不会有重边和自环。
- 调用
addEdge至多100次。 - 调用
shortestPath至多100次。
解题思路
方法一:Dijsktra 算法
在初始化函数中,我们先用邻接矩阵 存储图的边权,其中 表示从节点 到节点 的边权,如果 和 之间没有边,则 的值为 。
在 addEdge 函数中,我们更新 的值为 。
在 shortestPath 函数中,我们使用 Dijsktra 算法求从节点 到节点 的最短路径,其中 表示从节点 到节点 的最短路径, 表示节点 是否已经被访问过。我们初始化 为 ,其余的 均为 。然后我们遍历 次,每次找到当前未被访问过的节点 ,使得 最小。然后我们将节点 标记为已访问,然后更新 的值为 。最后我们返回 ,如果 为 ,则说明从节点 到节点 不存在路径,返回 。
时间复杂度 ,空间复杂度 。其中 为节点数,而 为 shortestPath 函数的调用次数。
class Graph:
def __init__(self, n: int, edges: List[List[int]]):
self.n = n
self.g = [[inf] * n for _ in range(n)]
for f, t, c in edges:
self.g[f][t] = c
def addEdge(self, edge: List[int]) -> None:
f, t, c = edge
self.g[f][t] = c
def shortestPath(self, node1: int, node2: int) -> int:
dist = [inf] * self.n
dist[node1] = 0
vis = [False] * self.n
for _ in range(self.n):
t = -1
for j in range(self.n):
if not vis[j] and (t == -1 or dist[t] > dist[j]):
t = j
vis[t] = True
for j in range(self.n):
dist[j] = min(dist[j], dist[t] + self.g[t][j])
return -1 if dist[node2] == inf else dist[node2]
# Your Graph object will be instantiated and called as such:
# obj = Graph(n, edges)
# obj.addEdge(edge)
# param_2 = obj.shortestPath(node1,node2)
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | complexity per query is O(M + N*V^2 + V^3) considering adjacency updates and Dijkstra runs; space complexity is O(V^2) for the adjacency matrix storing all edge costs. |
| 空间 | O(V^2) |
面试官常问的追问
外企场景- question_mark
Checking if you understand dynamic graph updates and how shortest paths can change with new edges.
- question_mark
Observing whether you optimize repeated shortest path queries rather than recalculating all paths naively.
- question_mark
Evaluating your choice between adjacency list vs adjacency matrix for trade-offs in update vs query speed.
常见陷阱
外企场景- error
Recomputing all shortest paths globally after each edge addition, leading to unnecessary overhead.
- error
Using BFS instead of Dijkstra for weighted graphs, resulting in incorrect path costs.
- error
Failing to handle the case when no path exists and returning invalid distances instead of -1.
进阶变体
外企场景- arrow_right_alt
Support undirected weighted graphs with similar dynamic edge additions and shortest path queries.
- arrow_right_alt
Allow multiple edges between nodes and compute the shortest path considering only the minimum-cost edge.
- arrow_right_alt
Optimize for batch shortest path queries where multiple paths are requested after a sequence of edge additions.