Floyd Warshall All Pairs Shortest Path in DSA Javascript - Time & Space Complexity
We want to understand how the time needed to find shortest paths between all pairs of points grows as the number of points increases.
How does the running time change when we add more points to the map?
Analyze the time complexity of the following code snippet.
const floydWarshall = (graph) => {
const dist = graph.map(row => row.slice());
const n = graph.length;
for (let k = 0; k < n; k++) {
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
if (dist[i][k] + dist[k][j] < dist[i][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
return dist;
};
This code finds the shortest distance between every pair of points in a graph using three nested loops.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The triple nested loops that check and update distances between all pairs through an intermediate point.
- How many times: Each loop runs n times, so the inner operation runs n x n x n = n³ times.
As the number of points (n) increases, the number of operations grows very fast because we check every pair through every possible intermediate point.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 1,000 |
| 100 | 1,000,000 |
| 1000 | 1,000,000,000 |
Pattern observation: When n grows 10 times, operations grow 1000 times, showing a cubic growth pattern.
Time Complexity: O(n³)
This means the time needed grows roughly with the cube of the number of points, so adding more points makes the work much heavier.
[X] Wrong: "Since there are three loops, the time complexity is just O(n) because loops run one after another."
[OK] Correct: The loops are nested inside each other, so the total work multiplies, not adds, making it O(n³), not O(n).
Understanding this cubic time complexity helps you explain why Floyd Warshall is good for small graphs but not for very large ones, showing your grasp of algorithm efficiency.
"What if we replaced the triple nested loops with a recursive approach that splits the graph? How might that affect the time complexity?"
Practice
Solution
Step 1: Understand Floyd Warshall's goal
The Floyd Warshall algorithm calculates shortest paths between every pair of vertices in a weighted graph.Step 2: Differentiate from other algorithms
Unlike Dijkstra's algorithm which finds shortest paths from one source, Floyd Warshall finds paths for all pairs.Final Answer:
To find the shortest paths between all pairs of vertices in a weighted graph -> Option CQuick Check:
All pairs shortest path = Floyd Warshall [OK]
- Confusing with Dijkstra's single source shortest path
- Thinking it detects cycles
- Assuming it sorts vertices
dist for Floyd Warshall in JavaScript given a graph adjacency matrix graph?Solution
Step 1: Understand deep copy necessity
We need a deep copy of the 2D array so changes to dist do not affect graph.Step 2: Check each option for deep copy
const dist = graph.map(row => row.slice()); uses map and slice to copy each row array, creating a deep copy. Others create shallow copies.Final Answer:
const dist = graph.map(row => row.slice()); -> Option AQuick Check:
Deep copy with map and slice = const dist = graph.map(row => row.slice()); [OK]
- Using shallow copy causing original graph to change
- Using spread operator which copies only top-level array
- Using map without slice copying references
const graph = [ [0, 3, Infinity], [2, 0, 5], [Infinity, 1, 0] ];
Solution
Step 1: Initialize dist matrix same as graph
dist = [[0,3,∞],[2,0,5],[∞,1,0]]Step 2: Update dist using Floyd Warshall iterations
Check paths through each vertex k=0,1,2:
k=0: dist[2][0] = min(∞, dist[2][0]+dist[0][0])=∞ no change
k=1: dist[0][2] = min(∞, dist[0][1]+dist[1][2])=3+5=8
dist[2][0] = min(∞, dist[2][1]+dist[1][0])=1+2=3
k=2: no shorter paths found
Final dist = [[0,3,8],[2,0,5],[3,1,0]]Final Answer:
[[0, 3, 8], [2, 0, 5], [3, 1, 0]] -> Option DQuick Check:
Updated shortest paths matrix = [[0, 3, 8], [2, 0, 5], [3, 1, 0]] [OK]
- Not updating paths through intermediate vertices
- Confusing Infinity with zero
- Missing updates for indirect paths
for (let k = 0; k < V; k++) {
for (let i = 0; i < V; i++) {
for (let j = 0; j < V; j++) {
if (dist[i][k] + dist[k][j] < dist[i][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}Solution
Step 1: Analyze addition of distances
Adding dist[i][k] + dist[k][j] without checking if either is Infinity can cause incorrect results or overflow.Step 2: Identify missing Infinity checks
Before adding, must ensure dist[i][k] !== Infinity and dist[k][j] !== Infinity to avoid invalid sums.Final Answer:
Missing check if dist[i][k] or dist[k][j] is Infinity before addition -> Option AQuick Check:
Check Infinity before sum to avoid errors [OK]
- Ignoring Infinity causing wrong updates
- Changing loop order unnecessarily
- Using <= instead of < causing redundant updates
Solution
Step 1: Understand negative cycle effect on dist matrix
Negative cycles cause the shortest path from a vertex to itself to become negative.Step 2: Check diagonal elements after Floyd Warshall
If any dist[i][i] < 0, it means a negative cycle exists involving vertex i.Final Answer:
By checking if any diagonal element dist[i][i] becomes negative -> Option BQuick Check:
Negative cycle detected if dist[i][i] < 0 [OK]
- Checking off-diagonal elements for negative cycles
- Confusing Infinity with negative cycles
- Assuming sum of distances indicates cycles
Ready to prove it?
Pass the test and this pattern moves unknown
