from typing import List
class Solution:
def updateMatrix(self, mat: List[List[int]]) -> List[List[int]]:
m, n = len(mat), len(mat[0])
dist = [[float('inf')] * n for _ in range(m)] # STEP 1: Initialize distances
for i in range(m):
for j in range(n):
if mat[i][j] == 0:
dist[i][j] = 0 # STEP 2: Set zero distances
for i in range(m):
for j in range(n):
if i > 0:
dist[i][j] = min(dist[i][j], dist[i-1][j] + 1) # STEP 3-8: First pass top-left to bottom-right
if j > 0:
dist[i][j] = min(dist[i][j], dist[i][j-1] + 1)
for i in range(m-1, -1, -1):
for j in range(n-1, -1, -1):
if i < m - 1:
dist[i][j] = min(dist[i][j], dist[i+1][j] + 1) # STEP 9-12: Second pass bottom-right to top-left
if j < n - 1:
dist[i][j] = min(dist[i][j], dist[i][j+1] + 1)
return dist # STEP 13: Return final distances
📊
01 Matrix - Watch the Algorithm Execute, Step by Step
Watching each update step reveals how distances propagate through the matrix, making the dynamic programming approach intuitive and clear.
Step 1/13
·Active fill★Answer cell
Visiting: none
0,0
0,1
0,2
1,0
1,1
1,2
2,0
2,1
2,2
Visiting: none
0,0
0,1
0,2
1,0
1,1
1,2
2,0
2,1
2,2
Visiting: 0,0
0,0
0,1
0,2
1,0
1,1
1,2
2,0
2,1
2,2
Visiting: 0,1
0,0
0,1
0,2
1,0
1,1
1,2
2,0
2,1
2,2
Visiting: 1,1
0,0
0,1
0,2
1,0
1,1
1,2
2,0
2,1
2,2
Visiting: 2,0
2,0
2,1
2,2
0,0
0,1
0,2
1,0
1,1
1,2
Visiting: 2,1
2,1
2,2
0,0
0,1
0,2
1,0
1,1
1,2
2,0
Visiting: 2,2
2,2
0,0
0,1
0,2
1,0
1,1
1,2
2,0
2,1
Visiting: 2,2
2,2
0,0
0,1
0,2
1,0
1,1
1,2
2,0
2,1
Visiting: 2,1
2,1
2,2
0,0
0,1
0,2
1,0
1,1
1,2
2,0
Visiting: 1,1
1,1
2,1
2,2
0,0
0,1
0,2
1,0
1,2
2,0
Visiting: 0,0
0,0
1,0
0,1
0,2
1,1
1,2
2,0
2,1
2,2
Visiting: none
0,0
0,1
0,2
1,0
1,1
1,2
2,0
2,1
2,2
Key Takeaways
✓ The two-pass dynamic programming approach efficiently computes shortest distances from zero cells without explicit BFS or DFS.
This insight is hard to see from code alone because the distance updates look like simple min operations, but watching the propagation clarifies the logic.
✓ The first pass propagates distances from top-left to bottom-right, and the second pass refines them from bottom-right to top-left.
Seeing the order of updates visually helps understand why two passes are necessary to capture all neighbor influences.
✓ Distance values never increase during updates; they only decrease or stay the same, ensuring convergence to minimal distances.
Watching each update step shows how the algorithm maintains and improves distance estimates, which is less obvious from static code.
Practice
(1/5)
1. Consider the following Python code implementing flood fill using DFS. Given the input image = [[1,1,1],[1,1,0],[1,0,1]], starting pixel (sr=1, sc=1), and newColor=2, what is the final image returned?
easy
A. [[1,1,1],[1,2,0],[1,0,1]]
B. [[2,2,2],[2,2,0],[2,0,2]]
C. [[2,2,2],[2,2,0],[2,0,1]]
D. [[2,2,2],[2,2,2],[2,2,2]]
Solution
Step 1: Trace dfs starting at (1,1) with original color=1
The pixel at (1,1) is recolored to 2. Its neighbors with color 1 are (0,1), (2,1) is 0 so skipped, (1,0), and (1,2) is 0 skipped.
Step 2: Recursively recolor connected pixels with color 1
All connected pixels with color 1 reachable from (1,1) are recolored to 2, resulting in [[2,2,2],[2,2,0],[2,0,1]]. The pixel at (2,2) remains 1 as it is not connected 4-directionally.
Final Answer:
Option C -> Option C
Quick Check:
Only connected pixels with original color changed [OK]
Hint: Trace DFS calls carefully to find connected pixels [OK]
Common Mistakes:
Changing pixels diagonally connected
Forgetting to check boundaries
2. What is the time complexity of the optimal Dijkstra-based algorithm for finding the cheapest flight within K stops, given n cities and E flights? Assume the graph is represented as adjacency lists and a min-heap is used.
A) O(n^2) because we may visit all nodes multiple times.
B) O(E log E) because each edge can be pushed into the heap once.
C) O(n log n) because Dijkstra runs in that time on sparse graphs.
D) O(K * E) because we relax edges up to K times.
medium
A. O(n^2) because we may visit all nodes multiple times.
B. O(K * E) because we relax edges up to K times.
C. O(E log E) because each edge can be pushed into the heap once.
D. O(n log n) because Dijkstra runs in that time on sparse graphs.
Solution
Step 1: Identify heap operations
Each edge can be pushed into the heap at most once per stops count, but stops ≤ K limits pushes. The heap size is bounded by O(E).
Step 2: Analyze complexity
Each push/pop operation costs O(log E), so total time is O(E log E). The stops constraint prevents exponential blowup.
Hint: Heap operations on edges dominate complexity [OK]
Common Mistakes:
Assuming O(n^2) from classic Dijkstra on adjacency matrix
Ignoring that stops limit expansions
Confusing Bellman-Ford complexity with this approach
3. Examine the following code snippet implementing the Network Delay Time using Bellman-Ford. Which line contains a subtle bug that can cause incorrect results on graphs with unreachable nodes?
medium
A. Line 5: Missing check if dist[u] is infinity before relaxation
B. Line 7: Incorrect comparison operator in relaxation condition
C. Line 10: Breaking early when no updates is incorrect
D. Line 12: Returning -1 instead of max distance is wrong
Solution
Step 1: Analyze relaxation condition at line 5
It lacks a check if dist[u] is infinity, so dist[u] + w can be infinity + w, causing incorrect updates.
Step 2: Other lines are correct: early break optimizes, comparison operator is correct, and returning -1 for unreachable nodes is expected
Thus, the bug is the missing dist[u] != infinity check before relaxation.
Hint: Always check dist[u] != infinity before relaxing edges [OK]
Common Mistakes:
Forgetting to check dist[u] before relaxation
Misunderstanding early break optimization
Incorrectly handling unreachable nodes
4. Suppose the Keys and Rooms problem is modified so that keys can be reused infinitely (i.e., you can revisit rooms multiple times). Which of the following changes to the algorithm is necessary to correctly determine if all rooms can be visited?
hard
A. Remove the visited array and perform DFS without tracking visited rooms
B. Use BFS with a queue and mark rooms as visited when enqueued to avoid infinite loops
C. Keep the visited array but reset it after each DFS call to allow revisits
D. Use a counter to limit the number of visits per room to prevent infinite recursion
Solution
Step 1: Understand infinite reuse of keys means cycles are possible
Without marking visited before enqueueing, BFS can enqueue the same room multiple times causing inefficiency or infinite loops.
Step 2: Use BFS with visited marking on enqueue
Marking visited when enqueuing prevents multiple enqueues of the same room, ensuring termination and correctness.
Step 3: Why other options fail
Removing visited causes infinite loops; resetting visited loses progress; limiting visits is inefficient and complex.
Final Answer:
Option B -> Option B
Quick Check:
BFS with visited marking on enqueue is standard for graphs with cycles [OK]
Hint: Mark visited when enqueuing in BFS to handle cycles [OK]
Common Mistakes:
Removing visited causes infinite loops
Resetting visited loses track of progress
Counting visits is inefficient and unnecessary
5. Suppose the problem changes: fresh oranges can become rotten multiple times, and rot can spread back to previously rotten oranges if it results in a faster rot time. Which modification to the DFS-based solution correctly handles this scenario?
hard
A. Switch to a brute force simulation updating the grid minute by minute until no changes
B. Keep the original DFS with pruning but run it multiple times until no updates occur
C. Use a multi-source BFS but do not track times, just mark visited once
D. Remove the pruning condition that skips DFS if time_grid[r][c] <= time, allowing revisits with better times
Solution
Step 1: Understand new rot dynamics
Rot can improve previously recorded rot times, so pruning based on time_grid[r][c] <= time is invalid.
Step 2: Modify DFS to allow revisits with better times
Removing pruning condition enables DFS to update time_grid when a faster rot path is found.
Step 3: Confirm correctness
This ensures all cells have minimum rot times even if rot spreads back to previously rotten oranges.
Final Answer:
Option D -> Option D
Quick Check:
Allowing revisits with better times handles dynamic rot spread correctly [OK]
Hint: Allow revisits if they improve rot time [OK]
Common Mistakes:
Keeping pruning causes stale times
Using BFS without time tracking
Brute force is inefficient
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.