You are given an m x n
integer matrix grid
where each cell is either 0
(empty) or 1
(obstacle). You can move up, down, left, or right from and to an empty cell in one step.
Return the minimum number of steps to walk from the upper left corner (0, 0)
to the lower right corner (m - 1, n - 1)
given that you can eliminate at most k
obstacles. If it is not possible to find such walk return -1
.
Example 1:
Input: grid = [[0,0,0],[1,1,0],[0,0,0],[0,1,1],[0,0,0]], k = 1 Output: 6 Explanation: The shortest path without eliminating any obstacle is 10. The shortest path with one obstacle elimination at position (3,2) is 6. Such path is (0,0) -> (0,1) -> (0,2) -> (1,2) -> (2,2) -> (3,2) -> (4,2).
Example 2:
Input: grid = [[0,1,1],[1,1,1],[1,0,0]], k = 1 Output: -1 Explanation: We need to eliminate at least two obstacles to find such a walk.
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 40
1 <= k <= m * n
grid[i][j]
is either 0
or 1
.grid[0][0] == grid[m - 1][n - 1] == 0
This problem asks for the minimum number of steps to reach the bottom-right corner of a grid from the top-left corner, given that you can eliminate at most k
obstacles. The solution uses a Breadth-First Search (BFS) algorithm.
Approach:
Base Case: If k
is large enough to remove all possible obstacles along the shortest path (without considering obstacles), the shortest path is simply the sum of rows and columns minus 1.
BFS Implementation: The core of the solution is a BFS traversal of the grid. Each node in the BFS queue represents a state (row, column, remaining_obstacles)
.
State Representation: The state (row, column, remaining_obstacles)
is crucial. It keeps track of not only the current cell's coordinates but also how many obstacles can still be removed.
Exploration: At each step, we explore the four adjacent cells (up, down, left, right). For each neighbor:
(neighbor_row, neighbor_column, remaining_obstacles)
to the queue if it hasn't been visited before.remaining_obstacles > 0
), we add the state (neighbor_row, neighbor_column, remaining_obstacles - 1)
to the queue if it hasn't been visited before.Visited States: We use a 3D boolean array vis
to keep track of visited states. This prevents cycles and ensures we find the shortest path. The three dimensions correspond to row, column, and remaining obstacles.
Termination: The BFS terminates when:
(m-1, n-1)
. The number of steps taken is returned.Time Complexity: O(M * N * K), where M and N are the dimensions of the grid and K is the maximum number of obstacles allowed to be removed. In the worst case, we might visit each cell with each possible value of remaining obstacles.
Space Complexity: O(M * N * K), dominated by the vis
array used to track visited states.
from collections import deque
class Solution:
def shortestPath(self, grid: List[List[int]], k: int) -> int:
m, n = len(grid), len(grid[0])
# Base case: Sufficient k to remove all obstacles along the shortest path
if k >= m + n - 3:
return m + n - 2
q = deque([(0, 0, k)]) # Queue of (row, col, remaining_obstacles)
vis = {(0, 0, k)} # Set to track visited states
ans = 0 # Steps taken
while q:
ans += 1
for _ in range(len(q)): #Process all nodes at current distance
i, j, cur_k = q.popleft()
# Check for target
if i == m - 1 and j == n - 1:
return ans
for a, b in [[0, -1], [0, 1], [1, 0], [-1, 0]]:
x, y = i + a, j + b
if 0 <= x < m and 0 <= y < n:
if grid[x][y] == 0 and (x, y, cur_k) not in vis:
q.append((x, y, cur_k))
vis.add((x, y, cur_k))
elif grid[x][y] == 1 and cur_k > 0 and (x, y, cur_k - 1) not in vis:
q.append((x, y, cur_k - 1))
vis.add((x, y, cur_k - 1))
return -1 # No path found
The other language versions follow a similar structure, adapting the syntax and data structures to the specific language. The core algorithm remains the same BFS with state tracking.