Dijkstra's Algorithm Single Source Shortest Path in DSA Typescript - Time & Space Complexity
We want to understand how the time needed to find shortest paths grows as the graph gets bigger.
How does the algorithm's work increase when there are more points and connections?
Analyze the time complexity of the following code snippet.
function dijkstra(graph: Array>, source: number): number[] {
const dist = Array(graph.length).fill(Infinity);
dist[source] = 0;
const visited = new Set();
const pq = new MinPriorityQueue();
pq.enqueue(source, 0);
while (!pq.isEmpty()) {
const { element: u } = pq.dequeue();
if (visited.has(u)) continue;
visited.add(u);
for (const [v, weight] of graph[u]) {
if (!visited.has(v) && dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
pq.enqueue(v, dist[v]);
}
}
}
return dist;
}
This code finds the shortest distance from one starting point to all others in a weighted graph using a priority queue.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The while loop runs until all nodes are visited, and inside it, the for loop checks neighbors of the current node.
- How many times: The while loop runs up to V times (number of nodes), and the for loop runs for each edge connected to the current node, totaling E edges checked.
As the graph grows, the number of nodes (V) and edges (E) increase, affecting how many times the loops run.
| Input Size (V, E) | Approx. Operations |
|---|---|
| 10 nodes, 20 edges | About 10 dequeue operations and 20 edge relaxations |
| 100 nodes, 500 edges | About 100 dequeue operations and 500 edge relaxations |
| 1000 nodes, 5000 edges | About 1000 dequeue operations and 5000 edge relaxations |
Pattern observation: The work grows roughly with the number of nodes plus the number of edges.
Time Complexity: O((V + E) log V)
This means the time grows with the number of nodes and edges, multiplied by the cost of managing the priority queue.
[X] Wrong: "Dijkstra's algorithm always runs in simple linear time O(V + E)."
[OK] Correct: Managing the priority queue adds a logarithmic factor, so the actual time depends on log V operations for each node or edge processed.
Understanding this time complexity helps you explain how your solution scales and why using a priority queue is important for efficiency.
"What if we used a simple array instead of a priority queue? How would the time complexity change?"
Practice
Solution
Step 1: Understand the algorithm's goal
Dijkstra's Algorithm is designed to find the shortest distance from one starting point (source) to every other point in a graph.Step 2: Compare with other graph algorithms
Minimum spanning tree algorithms find a tree connecting all vertices with minimum total weight, cycle detection finds loops, and topological sort orders vertices. These are different tasks.Final Answer:
To find the shortest path from a single source to all other vertices -> Option CQuick Check:
Dijkstra's Algorithm = shortest paths from source [OK]
- Confusing shortest path with minimum spanning tree
- Thinking it detects cycles
- Mixing it with topological sorting
Solution
Step 1: Understand initialization requirements
Distances start as Infinity except the source vertex which is 0.Step 2: Check each code snippet
const dist: number[] = Array(5).fill(Infinity); dist[0] = 0; correctly fills with Infinity and sets source distance to 0. const dist: number[] = new Array(5).map(() => 0); fills with 0 incorrectly. const dist: number[] = Array(5).fill(0); dist[0] = Infinity; fills with 0 and sets source to Infinity, wrong. const dist: number[] = Array(5).fill(null); dist[0] = 0; fills with null, which is invalid for numeric distances.Final Answer:
const dist: number[] = Array(5).fill(Infinity); dist[0] = 0; -> Option AQuick Check:
Distance array init = Infinity except source 0 [OK]
- Using map on new Array without fill (returns undefined)
- Setting all distances to 0 initially
- Using null instead of numeric values
const graph = new Map>();
graph.set(0, [[1, 4], [2, 1]]);
graph.set(1, []);
graph.set(2, [[1, 2]]);
const dist = Array(3).fill(Infinity);
dist[0] = 0;
const visited = new Set<number>();
while (visited.size < 3) {
let u = -1;
let minDist = Infinity;
for (let i = 0; i < 3; i++) {
if (!visited.has(i) && dist[i] < minDist) {
minDist = dist[i];
u = i;
}
}
if (u === -1) break;
visited.add(u);
for (const [v, w] of graph.get(u) || []) {
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
}
}
}
console.log(dist);Solution
Step 1: Initialize distances and start from source 0
dist = [0, Infinity, Infinity], visited = {}.Step 2: Pick unvisited vertex with smallest dist and update neighbors
Pick 0: update dist[1] = 4, dist[2] = 1. visited = {0}. Pick 2 (dist=1): update dist[1] = min(4, 1+2=3) = 3. visited = {0,2}. Pick 1 (dist=3): no neighbors. visited = {0,1,2}.Final Answer:
[0, 3, 1] -> Option DQuick Check:
Distances after updates = [0, 3, 1] [OK]
- Not updating dist[1] from 4 to 3 via vertex 2
- Picking wrong vertex with smallest distance
- Ignoring visited set causing infinite loops
const graph = new Map>();
graph.set(0, [[1, 7], [2, 9], [5, 14]]);
graph.set(1, [[2, 10], [3, 15]]);
graph.set(2, [[3, 11], [5, 2]]);
graph.set(3, [[4, 6]]);
graph.set(4, [[5, 9]]);
graph.set(5, []);
const dist: number[] = new Array(graph.size);
dist.fill(Infinity);
dist[0] = 0;
const visited = new Set<number>();
while (visited.size < graph.size) {
let u = -1;
let minDist = Infinity;
for (let i = 0; i < graph.size; i++) {
if (!visited.has(i) && dist[i] < minDist) {
minDist = dist[i];
u = i;
}
}
visited.add(u);
for (const [v, w] of graph.get(u) || []) {
if (dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
}
}
}Solution
Step 1: Analyze the selection of vertex u
If no unvisited vertex has finite dist, u remains -1.Step 2: Check visited addition without validation
Code adds u to visited without checking if u === -1, which can cause adding -1 and errors.Final Answer:
Adding vertex u to visited set before checking if u is -1 -> Option BQuick Check:
Check u !== -1 before visited.add(u) [OK]
- Ignoring u === -1 case causing infinite loops
- Confusing graph.size with array length
- Not initializing dist array properly
Solution
Step 1: Calculate shortest distances step-by-step
Start dist: [0,∞,∞,∞,∞] From 0: dist[1]=2, dist[2]=4 From 1: dist[2]=min(4,2+1=3)=3, dist[3]=2+7=9 From 2: dist[4]=3+3=6 From 3: dist[4]=min(6,9+1=10)=6Step 2: Identify shortest distance to vertex 4
Shortest distance to vertex 4 is 6 via path 0->1->2->4.Final Answer:
6 -> Option AQuick Check:
Shortest path distance to 4 = 6 [OK]
- Ignoring shorter path via vertex 2
- Adding edges incorrectly
- Assuming direct edge is always shortest
Ready to prove it?
Pass the test and this pattern moves unknown
