1293. Shortest Path in a Grid with Obstacles Elimination

66 阅读2分钟

image.png

image.png

方法

这段代码是为了解决一个特定的问题:在一个由 0 和 1 组成的二维网格中找到从左上角到右下角的最短路径,同时允许在路径中最多消除 k 个障碍物(由 1 表示)。下面是对这段代码的详细解释:

  • 方向数组(directions):

这是一个二维数组,表示四个可能的移动方向:上(-1,0)、下(1,0)、左(0,-1)和右(0,1)。

  • 函数 shortestPath:

如果 k 大于或等于 m + n - 3,则直接返回 m + n - 2。这是因为在没有障碍的情况下,到达右下角需要的最少步数是 m + n - 2,如果 k 足够大,可以直接越过所有障碍物。

  • 状态标记数组(flag):

boolean[][][] flag 用来标记在给定位置 (m, n) 时,剩余可消除障碍物的机会数 k 的状态是否已经被访问过。

  • 广度优先搜索(BFS):

使用队列 q 进行广度优先搜索。 初始状态为 {0, 0, k},表示从 (0, 0) 开始,有 k 个障碍物可以消除。 在搜索的每一步,我们检查四个方向,并对每个方向进行以下操作: 确保新的位置没有越界。

如果下一个位置不是障碍物,并且这个状态没有被访问过,将其添加到队列中

如果下一个位置是障碍物,且当前还有移除障碍物的机会,且这个状态没有被访问过,也将其添加到队列中

  • 寻找路径并返回结果:

在 BFS 过程中,如果到达了右下角 (m-1, n-1),则返回当前步数 step 作为最短路径的长度。 如果搜索结束后仍未到达右下角,则返回 -1,表示没有找到合适的路径。

class Solution {
    public int shortestPath(int[][] grid, int k) {
        int m = grid.length, n = grid[0].length;

         // 如果k足够大以至于可以直接穿越所有障碍物,则直接返回最短路径长度
        if (k > m + n - 2) {
            return m + n - 2;
        }

        // 方向
        int[] dirM = new int[]{-1, 1, 0, 0}; // up down left right
        int[] dirN = new int[]{0, 0, -1, 1};

        Queue<int[]> queue = new LinkedList<>();
        queue.offer(new int[]{0, 0, k});

        // 在位置 (m, n) 时,剩余可消除障碍物的机会数 k 的状态是否已经被访问过
        boolean[][][] visited = new boolean[m][n][k + 1];
        visited[0][0][k] = true;

        int res = 0;
        while (!queue.isEmpty()) {
            res++;
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                int[] arr = queue.poll();
                int curM = arr[0];
                int curN = arr[1];
                int curK = arr[2];
                
                for (int j = 0; j < 4; j++) {
                    int nextM = curM + dirM[j];
                    int nextN = curN + dirN[j];

                    
                    if (nextM >= 0 && nextM < m && nextN >= 0 && nextN < n) {
                        // 如果下一个位置是空的且未访问过
                        if (grid[nextM][nextN] == 0 && !visited[nextM][nextN][curK]) {
                            // 到达右下角
                            if (nextM == m - 1 && nextN == n - 1) {
                                return res;
                            }
                            visited[nextM][nextN][curK] = true;
                            queue.offer(new int[]{nextM, nextN, curK});
                        } else if (grid[nextM][nextN] == 1 && curK > 0 &&!visited[nextM][nextN][curK - 1]) {                     
                            //如果下一个位置是障碍物且还有消除机会
                            visited[nextM][nextN][curK - 1] = true;
                            queue.offer(new int[]{nextM, nextN, curK - 1});
                        }
                    }
                }
            }
        }
        return -1;

    }
}