Pattern #58

Dijkstra's Algorithm

Important interview questions, cheapest-node-first thinking, min-heap relaxation, stale entries, path reconstruction, weighted-grid variants, and Go templates.

Must Solve

15 core questions — solve these first.

  1. 1.Network Delay Time
    medium
  2. 2.Path With Minimum Effort
    medium
  3. 3.Swim in Rising Water
    hard
  4. 4.Cheapest Flights Within K Stops
    medium
  5. 5.Number of Ways to Arrive at Destination
    medium
  6. 6.Minimum Cost to Reach Destination
    medium
  7. 7.Minimum Cost Path in a Weighted Grid
    medium
  8. 8.Reachable Nodes in Subdivided Graph
    hard
  9. 9.Path With Maximum Probability
    medium
  10. 10.Minimum Cost to Make at Least One Valid Path in a Grid
    hard
  11. 11.Minimum Obstacle Removal to Reach Corner
    hard
  12. 12.Find the City With Smallest Number of Neighbors
    medium
  13. 13.Minimum Weighted Subgraph With Required Paths
    hard
  14. 14.Second Minimum Time to Reach Destination
    hard
  15. 15.Dijkstra Shortest Path with Path Reconstruction
    medium

Also Important

7 more weighted shortest-path patterns.

  1. 16.Shortest Path in Weighted Undirected Graph
    medium
  2. 17.Shortest Path in Weighted Directed Graph
    medium
  3. 18.Multi-Source Dijkstra
    medium
  4. 19.Dijkstra with Extra State
    hard
  5. 20.Dijkstra on Grid
    medium
  6. 21.Dijkstra with Time / Constraints
    hard
  7. 22.A* Search — Practical Extension
    hard

How to Think

  1. Weighted shortest path and all weights non-negative?Dijkstra
  2. Main data structure?Min Heap / Priority Queue
  3. What does the heap store?(distance, node)
  4. What operation repeats?Relax outgoing edges
Take cheapest node
↓
Skip it if the heap entry is stale
↓
Relax neighbors
↓
Push every improvement
↓
Repeat

Go Quick Reference — Core Dijkstra

The heap may contain multiple entries for one node. Process only the entry equal to the current best distance.

func dijkstra(n int, graph [][]Edge, start int) []int {
    dist := make([]int, n)
    for i := range dist { dist[i] = INF }
    dist[start] = 0
    pq := MinHeap{{dist: 0, node: start}}

    for pq.Len() > 0 {
        cur := heap.Pop(&pq).(State)
        if cur.dist != dist[cur.node] { continue } // stale
        for _, edge := range graph[cur.node] {
            nextDist := cur.dist + edge.weight
            if nextDist < dist[edge.to] {
                dist[edge.to] = nextDist
                heap.Push(&pq, State{nextDist, edge.to})
            }
        }
    }
    return dist
}
  • • Dijkstra is correct only when weights are non-negative.
  • • Early exit is safe when the target is popped with its current best distance.
  • • Do not mark visited when a node is merely discovered.

Variants & Path Reconstruction

Actual shortest path

On improvement:
parent[next] = node

Trace target → parent → start
Then reverse the sequence.

Count shortest paths

better: ways[next] = ways[node]
equal:  ways[next] += ways[node]

Minimax Dijkstra

For Minimum Effort or Rising Water, combine the path using max(currentCost, edgeCost), then minimize that value.

Extra state

If stops, time, or resources change future options, heap state and distance keys must include them.

Visual Memory Rule
Heap top        → cheapest known distance
Stale pop       → skip
Better neighbor → update + push
Target popped   → safe early exit
Negative edge   → invalid algorithm

Complexity

Adjacency list + binary heap
Time:  O((V + E) log V)
Space: O(V + E)

Dense matrix implementation
Time:  O(V²)

Heap operations add the logarithmic factor; use 64-bit distances when path sums can exceed int range.

Common Interview Mistakes

  • • Using Dijkstra with a negative edge
  • • Using a FIFO queue instead of a min heap
  • • Marking visited like BFS
  • • Forgetting to skip stale heap entries
  • • Reversing the heap order
  • • Adding only one direction for an undirected edge
  • • Overflowing distance sums or ignoring unreachable nodes
  • • Tracking node only when the real state has extra constraints

Interview Rules

Non-negative weights → Dijkstra
Heap               → (distance, node)
Pop                 → cheapest known state
Stale entry         → skip
Better route        → relax + push
Actual route        → parent array
Extra constraint    → extra state
Negative edge       → Bellman-Ford

Production Thinking

Network routing → minimize latency or routing cost from one origin.

Maps and logistics → weights represent time, distance, fuel, or toll.

Production warning → use int64 for large costs and skip stale heap entries.

Remember This

Dijkstra    → non-negative weighted graph
Priority    → total distance so far
Relaxation  → newDist < dist[next]
Stale entry → poppedDist != dist[node]
Actual path → parent array
Time        → O((V + E) log V)

💡 Golden Rule: Always expand the currently cheapest valid state, then relax its outgoing edges.