Dijkstra's Algorithm
Dijkstra's Algorithm is a GFG problem (Medium). You are given a connected, undirected, weighted graph with V vertices numbered 0 … V-1, as a list edges where edges[i] = [u, v, w] is an edge between u and v of weight w, and a source vertex src.
Return an array dist of length V where dist[i] is the shortest distance from src to vertex i.
- Every weight is non-negative. That condition is what makes Dijkstra's algorithm correct.
VandEgo up to 10⁶, so a min-heap that keeps the work near O(E log V) is the expected answer.
- 1 <= V <= 10⁶
- 1 <= E <= 10⁶
- 0 <= weight <= 10⁴ — non-negative only
- Use Bellman-Ford if any edge can be negative
Intuition
Dijkstra's algorithm grows a set of settled vertices, starting from the source. A settled vertex is one whose shortest distance is final and will never change.
- Pick: always settle the closest unsettled vertex next.
- Why that is safe: any other route to it must leave the settled set through a vertex that is already at least as far away. With non-negative weights, the rest of that route can only add distance, so nothing found later can beat it.
- Relax: after settling
u, check each neighbourv. Ifdist[u] + wis smaller than the best knowndist[v], lowerdist[v]. That update is called relaxing the edge.
A min-heap (priority queue) keyed by distance hands out the closest unsettled vertex in O(log V). When a distance is lowered, the old heap entry is left behind; it is stale (out of date) and is simply skipped when popped.
The demo below walks through a Dijkstra algorithm example on six vertices, including the stale entries it skips.
Reach for Dijkstra shortest path whenever the task is a single source shortest path on a weighted graph where no edge is negative: road maps, network delay (LeetCode 743), cheapest flights without a stop limit, path with minimum effort (LeetCode 1631). If every edge has the same weight, plain BFS does the same job in O(V + E). If an edge can be negative, use Bellman-Ford.
Approach
Before reading on: on the first example, which vertex would you settle second, and why is its distance already final? Then decide what to do when the heap hands you a vertex whose distance has since been improved.
Two ways to solve it
The heap hands out the closest unsettled vertex, and stale entries are skipped when popped.
- Finding the next vertex: O(log V) per pop.
- Fits: sparse graphs, like this one with E up to 10⁶.
- Extra state: the heap, up to E entries.
The standard answer for this problem.
Each round scans every vertex for the smallest unsettled distance, settles it, and relaxes its edges.
- Finding the next vertex: O(V) per round.
- Fits: dense graphs, where E is close to V².
- Extra state: a settled flag per vertex.
Too slow at V = 10⁶.
With up to 10⁶ vertices and edges, the heap avoids the V² scan, so it is the one to use here. The steps, code and live demo below follow the heap version; the array-scan code comes after the demo.
Build the adjacency list
For each [u, v, w], add (v, w) to adj[u] and (u, w) to adj[v], because the graph is undirected. Each vertex then reaches its neighbours directly instead of scanning the whole edge list.
Initialise distances and the heap
dist is infinity everywhere except dist[src] = 0. The heap starts with (0, src). The source is the only distance known for sure at the start.
Pop the closest vertex
Pop (d, u) with the smallest d:
- if
d > dist[u], the entry is stale (uwas already settled with a smaller distance), so skip it; - otherwise
uis settled now, anddist[u]is final.
Relax every edge out of u
For each (v, w) in adj[u]: if d + w < dist[v], set dist[v] = d + w and push (dist[v], v). A shorter path to u may also give a shorter path to each neighbour. A vertex is final when it is popped, not when it is pushed.
Stop when the heap is empty
Every reachable vertex has been settled once with its final distance. Return dist.
Dijkstra's Algorithm solution in Python | C++ | Java
Dijkstra with an array scan
Run V rounds. Each round picks the unsettled vertex with the smallest dist by a linear scan, stops if that distance is infinite, marks it settled, and relaxes its edges.
Common pitfalls
Processing stale heap entries
d, u = heapq.heappop(pq)
for v, w in adj[u]:
...d, u = heapq.heappop(pq)
if d > dist[u]:
continueThe answer stays correct, but a vertex whose distance was lowered k times is expanded k times. On dense graphs that turns O(E log V) into much more work, and it is the usual reason a Dijkstra solution times out.
Using Dijkstra with negative edge weights
# directed: 0→1 (2), 0→2 (5), 2→1 (-4) # 1 is settled at distance 2 and treated as final
# any negative edge: use Bellman-Ford # dist[1] = 5 + (-4) = 1
Dijkstra is correct only because a popped vertex is final. With a visited set, vertex 1 is locked at 2 before the cheaper route through 2 is found. The lazy version on this page happens to reopen it, but then vertices can be expanded again and again, and on some graphs the running time becomes exponential.
Marking a vertex visited when it is pushed
if v not in seen:
seen.add(v)
heapq.heappush(pq, (d + w, v))if d + w < dist[v]:
dist[v] = d + w
heapq.heappush(pq, (dist[v], v))That is BFS logic. In the second example vertex 3 is first reached by the direct edge of cost 10 and would be locked at 10, although the path through 1 and 2 costs 3. A vertex is final when it is popped, not when it is first seen.
Complexity
Dijkstra vs other shortest-path algorithms
The weights and the number of sources decide which algorithm is correct and fastest.
| Algorithm | Weights | Sources | Time |
|---|---|---|---|
| BFS | all equal | one | O(V + E) |
| 0-1 BFS (deque) | only 0 or 1 | one | O(V + E) |
| Dijkstra (min-heap) | non-negative | one | O((V + E) log V) |
| Bellman-Ford | any, detects negative cycles | one | O(V · E) |
| Floyd Warshall | any, detects negative cycles | all pairs | O(V³) |
Dijkstra's Algorithm FAQ
How does Dijkstra's algorithm work?
- Start:
dist[src] = 0, every other distance infinity, heap =[(0, src)]. - Repeat: pop the vertex
uwith the smallest distance; skip it if the entry is stale (d > dist[u]). - Relax: for each edge
(u, v, w), ifdist[u] + w < dist[v], updatedist[v]and push it. - End: when the heap is empty,
distholds shortest distances. - Requirement: no negative edge weights.
- Complexity: O((V + E) log V) with a binary heap.
What is the time complexity of Dijkstra's algorithm?
O((V + E) log V) with a binary heap, since each edge may add one heap entry and each heap operation is O(log V).