Problem
You are given a 0-indexed 2D integer array grid
of size m x n
. Each
cell has one of two values:
0
represents an empty cell,1
represents an obstacle that may be removed.
You can move up, down, left, or right from and to an empty cell.
Return _theminimum number of obstacles to remove so you can move
from the upper left corner _(0, 0)
to the lower right corner(m - 1, n - 1)
.
Examples
Example 1:
$$ \begin{array}{|c|c|c|} \hline 0 & \times & \times \ \hline \times & \times & 0 \ \hline \times & \times & 0 \ \hline \end{array} \implies \begin{array}{|c|c|c|} \hline \colorbox{green} 0 & \colorbox{green}0 & \colorbox{green} 0 \ \hline \times & \times & \colorbox{green}{0} \ \hline \times & \times & \colorbox{green}{0} \ \hline \end{array} $$
Input: grid = [[0,1,1],[1,1,0],[1,1,0]]
Output: 2
Explanation: We can remove the obstacles at (0, 1) and (0, 2) to create a path from (0, 0) to (2, 2).
It can be shown that we need to remove at least 2 obstacles, so we return 2.
Note that there may be other ways to remove 2 obstacles to create a path.
Example 2:
$$ \begin{array}{|c|c|c|c|c|} \hline 0 & \times & 0 & 0 & 0 \ \hline 0 & \times & 0 & \times & 0 \ \hline 0 & 0 & 0 & \times & 0 \ \hline \end{array} $$
Input: grid = [[0,1,0,0,0],[0,1,0,1,0],[0,0,0,1,0]]
Output: 0
Explanation: We can move from (0, 0) to (2, 4) without removing any obstacles, so we return 0.
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 105
2 <= m * n <= 105
grid[i][j]
is either0
or1
.grid[0][0] == grid[m - 1][n - 1] == 0
Solution
Method 1 - Using BFS
Here is the approach:
- Problem Understanding:
- You need to find the minimum number of obstacles (1s) that need to be removed to travel from the top-left corner (0, 0) to the bottom-right corner (m-1, n-1) of a grid.
- Graph Search Algorithm:
- This problem is best approached using a shortest path algorithm in an unweighted grid with obstacles that can be removed.
- Breadth-First Search (BFS) is appropriate here, especially a variant called 0-1 BFS since there are only two types of cells (0s and 1s).
- 0-1 BFS:
- 0-1 BFS uses a deque (double-ended queue) to achieve the desired efficiency. In this approach, use the front of the deque for cells with value 0 and the back of the deque for cells with value 1.
- Start from the top-left cell, and for each cell, explore its neighbours. If a neighbour is an empty cell (0), add it to the front of the deque. If it’s an obstacle (1), add it to the back.
Code
Java
class Solution {
public int minimumObstacles(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
Deque<int[]> dq = new LinkedList<>();
int[][] dist = new int[m][n];
for (int[] row : dist) Arrays.fill(row, Integer.MAX_VALUE);
dist[0][0] = 0;
dq.addFirst(new int[]{0, 0});
int[][] dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
while (!dq.isEmpty()) {
int[] curr = dq.pollFirst();
int x = curr[0], y = curr[1];
for (int[] d : dirs) {
int nx = x + d[0], ny = y + d[1];
if (nx >= 0 && ny >= 0 && nx < m && ny < n) {
int ndist = dist[x][y] + grid[nx][ny];
if (ndist < dist[nx][ny]) {
dist[nx][ny] = ndist;
if (grid[nx][ny] == 0) {
dq.addFirst(new int[]{nx, ny});
} else {
dq.addLast(new int[]{nx, ny});
}
}
}
}
}
return dist[m-1][n-1];
}
}
Python
class Solution:
def minimumObstacles(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
dq = deque([(0, 0)])
dist = [[float('inf')] * n for _ in range(m)]
dist[0][0] = 0
dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)]
while dq:
x, y = dq.popleft()
for dx, dy in dirs:
nx, ny = x + dx, y + dy
if 0 <= nx < m and 0 <= ny < n:
new_dist = dist[x][y] + grid[nx][ny]
if new_dist < dist[nx][ny]:
dist[nx][ny] = new_dist
if grid[nx][ny] == 0:
dq.appendleft((nx, ny))
else:
dq.append((nx, ny))
return dist[m-1][n-1]
Complexity
- ⏰ Time complexity:
O(m * n)
, wherem
is the number of rows andn
is the number of columns since each cell is processed at most once. - 🧺 Space complexity:
O(m * n)
due to the space required for the deque and visited tracking.