Floyd Warshall All Pairs Shortest Path in DSA Go - 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.
func FloydWarshall(dist [][]int, n int) {
for k := 0; k < n; k++ {
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
if dist[i][k]+dist[k][j] < dist[i][j] {
dist[i][j] = dist[i][k] + dist[k][j]
}
}
}
}
}
This code updates the shortest distances between all pairs of points by checking if going through an intermediate point is shorter.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The triple nested loops that check and update distances.
- How many times: Each loop runs n times, so the inner check runs n x n x n = n³ times.
As the number of points (n) grows, the number of distance checks 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: The operations grow by the cube of n, so doubling n makes the work about eight times bigger.
Time Complexity: O(n³)
This means the time needed grows very quickly as the number of points increases, because we check all pairs through all intermediates.
[X] Wrong: "Since there are three loops, the time is just O(n) because loops run fast."
[OK] Correct: Each loop runs n times, so the total checks multiply, making it n x n x n = n³, which grows much faster than n.
Understanding this cubic growth helps you explain why Floyd Warshall is good for small graphs but not for very large ones, showing you know when to choose algorithms wisely.
"What if we replaced the triple nested loops with a recursive approach? How would the time complexity change?"
Practice
Solution
Step 1: Understand Floyd Warshall's goal
The Floyd Warshall algorithm is designed to find shortest paths between every pair of vertices in a weighted graph, including negative weights but no negative cycles.Step 2: Compare with other graph algorithms
Minimum spanning tree algorithms find a subset of edges connecting all vertices with minimum total weight, cycle detection finds cycles, and DFS is a traversal method. These are different from Floyd Warshall's all pairs shortest path goal.Final Answer:
To find the shortest paths between all pairs of vertices in a weighted graph -> Option DQuick Check:
Floyd Warshall = All pairs shortest paths [OK]
- Confusing Floyd Warshall with minimum spanning tree algorithms
- Thinking it only finds shortest path from one source
- Assuming it detects cycles
- Mixing it with traversal algorithms like DFS
dist for Floyd Warshall in Go, given graph as adjacency matrix and V as number of vertices?Solution
Step 1: Understand matrix copying in Go
In Go, to copy a 2D slice (matrix), you must copy each element individually. Assigning one slice to another copies the reference, not the data.Step 2: Analyze options
for i := 0; i < V; i++ { for j := 0; j < V; j++ { dist[i][j] = graph[i][j] } } copies each element explicitly, correctly initializingdist. for i := 0; i < V; i++ { dist[i] = graph[i] } copies slice references, not elements. dist = graph assigns reference, not copy. dist := make([]int, V*V) creates a 1D slice, not a 2D matrix.Final Answer:
for i := 0; i < V; i++ { for j := 0; j < V; j++ { dist[i][j] = graph[i][j] } } -> Option CQuick Check:
Copy element-wise for matrix copy [OK]
- Assigning slices directly causing shared references
- Using 1D slice instead of 2D for matrix
- Not initializing inner slices before assignment
- Assuming slice assignment copies data
graph := [][]int{
{0, 3, 9999, 7},
{8, 0, 2, 9999},
{5, 9999, 0, 1},
{2, 9999, 9999, 0},
}Solution
Step 1: Initialize distance matrix
Start with given graph matrix where 9999 means no direct edge. Distances on diagonal are 0.Step 2: Apply Floyd Warshall updates
Check all triples (i, j, k) and update dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]). After iterations, shortest paths are:
dist[0][2] = min(9999, 3+2) = 5
dist[0][3] = min(7, 3+2+1) = 6
dist[1][0] = min(8, 2+1+2) = 7
dist[1][3] = min(9999, 2+1) = 3
dist[2][0] = min(5, 1+2) = 3
dist[2][1] = min(9999, 1+2+3) = 6
dist[3][1] = min(9999, 2+3) = 5
dist[3][2] = min(9999, 2+3+2) = 7Final Answer:
[[0, 3, 5, 6], [7, 0, 2, 3], [3, 6, 0, 1], [2, 5, 7, 0]] -> Option AQuick Check:
Floyd Warshall updates shortest paths correctly [OK]
- Not updating paths through intermediate vertices
- Confusing no edge (9999) with zero
- Forgetting to update all pairs in nested loops
- Incorrectly summing distances
for k := 0; k < V; k++ {
for i := 0; i < V; i++ {
for 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: Understand the addition of distances
When dist[i][k] or dist[k][j] is infinity (e.g., 9999), adding them can cause integer overflow or incorrect comparisons.Step 2: Identify missing checks
The code does not check if dist[i][k] or dist[k][j] is infinity before adding. This can cause wrong updates to dist[i][j]. Proper code should skip addition if either is infinity.Final Answer:
Missing check for dist[i][k] or dist[k][j] being infinity before addition -> Option AQuick Check:
Check infinity before adding distances [OK]
- Ignoring infinity checks causing wrong updates
- Changing loop order unnecessarily
- Using <= instead of < does not fix logic
- Assuming code is correct without boundary checks
Solution
Step 1: Understand Floyd Warshall's limitation
Floyd Warshall computes shortest distances but does not store path details by default.Step 2: Use predecessor matrix for path reconstruction
By maintaining a predecessor matrix where predecessor[i][j] stores the vertex before j on the shortest path from i, we can reconstruct the path after the algorithm finishes.Step 3: Other options analysis
Storing all paths explicitly is inefficient. Running Dijkstra repeatedly is possible but less efficient for dense graphs. BFS is not suitable for weighted graphs.Final Answer:
Maintain a separate predecessor matrix updated during relaxation to track paths -> Option BQuick Check:
Predecessor matrix enables path reconstruction [OK]
- Not tracking predecessors, so no path info
- Trying to store all paths explicitly causing inefficiency
- Confusing BFS with weighted shortest path algorithms
- Using Dijkstra repeatedly instead of Floyd Warshall
Ready to prove it?
Pass the test and this pattern moves unknown
