到达角落需要移除障碍物的最小数目
难度:
标签:
题目描述
给你一个下标从 0 开始的二维整数数组 grid
,数组大小为 m x n
。每个单元格都是两个值之一:
0
表示一个 空 单元格,1
表示一个可以移除的 障碍物 。
你可以向上、下、左、右移动,从一个空单元格移动到另一个空单元格。
现在你需要从左上角 (0, 0)
移动到右下角 (m - 1, n - 1)
,返回需要移除的障碍物的 最小 数目。
示例 1:
输入:grid = [[0,1,1],[1,1,0],[1,1,0]] 输出:2 解释:可以移除位于 (0, 1) 和 (0, 2) 的障碍物来创建从 (0, 0) 到 (2, 2) 的路径。 可以证明我们至少需要移除两个障碍物,所以返回 2 。 注意,可能存在其他方式来移除 2 个障碍物,创建出可行的路径。
示例 2:
输入:grid = [[0,1,0,0,0],[0,1,0,1,0],[0,0,0,1,0]] 输出:0 解释:不移除任何障碍物就能从 (0, 0) 到 (2, 4) ,所以返回 0 。
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 105
2 <= m * n <= 105
grid[i][j]
为0
或1
grid[0][0] == grid[m - 1][n - 1] == 0
代码结果
运行时间: 691 ms, 内存: 41.9 MB
/*
* 思路:
* 使用广度优先搜索(BFS)和Java Stream API的组合来解决此问题。虽然Stream并不是非常适合处理状态变化和队列操作,
* 但我们可以在某些情况下使用Stream来简化代码。
*
* 具体步骤:
* 1. 使用优先队列实现BFS,计算到达每个位置的最小障碍物移除数量。
* 2. 使用Stream API处理方向数组并简化代码的某些部分。
*/
import java.util.*;
import java.util.stream.IntStream;
public class SolutionStream {
private static final int[][] DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public int minObstacleRemoval(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[][] dist = new int[m][n];
for (int i = 0; i < m; i++) {
Arrays.fill(dist[i], Integer.MAX_VALUE);
}
dist[0][0] = 0;
PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[2]));
pq.offer(new int[]{0, 0, 0});
while (!pq.isEmpty()) {
int[] curr = pq.poll();
int x = curr[0], y = curr[1], obstacles = curr[2];
if (x == m - 1 && y == n - 1) {
return obstacles;
}
IntStream.range(0, 4).forEach(i -> {
int nx = x + DIRECTIONS[i][0], ny = y + DIRECTIONS[i][1];
if (nx >= 0 && nx < m && ny >= 0 && ny < n) {
int nextObstacles = obstacles + grid[nx][ny];
if (nextObstacles < dist[nx][ny]) {
dist[nx][ny] = nextObstacles;
pq.offer(new int[]{nx, ny, nextObstacles});
}
}
});
}
return -1;
}
}
解释
方法:
本题解采用了广度优先搜索(BFS)的策略来找到从起点到终点移除最少障碍物的路径。为了实现这一点,代码使用了双端队列(deque)来处理两种情况:移动到空单元格和移动到障碍物单元格。如果是空单元格,则优先处理(加入队列前端),如果是障碍物,则稍后处理(加入队列尾部)。这样做的目的是尽可能地避免移除障碍物。同时,使用了一个二维数组 `distances` 来记录到每个位置的最小障碍物移除数,这有助于避免不必要的重复访问和更新。当达到终点时,即可返回当前位置的障碍物移除数。
时间复杂度:
O(m*n)
空间复杂度:
O(m*n)
代码细节讲解
🦆
在广度优先搜索(BFS)中使用双端队列(deque)的优势是什么,相比于普通队列有何不同?
▷🦆
为什么在处理到达每个单元格时考虑加入队列前端或队列尾部,这种区分对算法效率有何影响?
▷🦆
二维数组 `distances` 初始化为一个非常大的数(例如900000),这个数的选取有什么特别的意义或考虑吗?
▷🦆
如果在某个位置 `(x, y)` 的 `distances[x][y]` 值已经是最小障碍物移除数,再次更新这个位置是否有可能?这会不会影响算法的效率?
▷