[LeetCode]1293. 网格中的最短路径

题目

1293. 网格中的最短路径

1293. 网格中的最短路径
给你一个 m * n 的网格,其中每个单元格不是 0(空)就是 1(障碍物)。每一步,您都可以在空白单元格中上、下、左、右移动。

如果您 最多 可以消除 k 个障碍物,请找出从左上角 (0, 0) 到右下角 (m-1, n-1) 的最短路径,并返回通过该路径所需的步数。如果找不到这样的路径,则返回 -1 。

 

示例 1:



输入: grid = [[0,0,0],[1,1,0],[0,0,0],[0,1,1],[0,0,0]], k = 1
输出:6
解释:
不消除任何障碍的最短路径是 10。
消除位置 (3,2) 处的障碍后,最短路径是 6 。该路径是 (0,0) -> (0,1) -> (0,2) -> (1,2) -> (2,2) -> (3,2) -> (4,2).
示例 2:



输入:grid = [[0,1,1],[1,1,1],[1,0,0]], k = 1
输出:-1
解释:我们至少需要消除两个障碍才能找到这样的路径。
 

提示:

grid.length == m
grid[0].length == n
1 <= m, n <= 40
1 <= k <= m*n
grid[i][j]01
grid[0][0] == grid[m-1][n-1] == 0

解法

方法1:BFS

     int m, n;
        //右 下 左 上
        int[][] dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

        //我们还可以对搜索空间进行优化。注意到题目中 k 的上限为 m * n,但考虑一条从 (0, 0) 向下走到 (m - 1, 0) 再向右走到
        // (m - 1, n - 1) 的路径,它经过了 m + n - 1 个位置,其中起点 (0, 0) 和终点 (m - 1, n - 1) 没有障碍物,
        // 那么这条路径上最多只会有 m + n - 3 个障碍物。因此我们可以将 k 的值设置为 m + n - 3 与其本身的较小值
        // min(k, m + n - 3),将广度优先搜索的时间复杂度从 O(MNK) 降低至 (MN∗min(M+N,K))

        public int shortestPath(int[][] grid, int k) {
            m = grid.length;
            n = grid[0].length;
            //case ->
            //[[0]]
            //1
            if (m == 1 && n == 1) return 0;
//            if ( k >= m + n - 3){
//                return m + n - 2;
//            }
//            k = Math.min(k, m + n - 3);
            boolean[][][] vis = new boolean[m][n][k + 1];
            Queue<Position> q = new LinkedList<>();
            //标记访问的状态
            q.offer(new Position(0, 0, k));
            vis[0][0][k] = true;
            int steps = 0;
            while (!q.isEmpty()) {
                int size = q.size();
                steps++;
                for (int i = 0; i < size; i++) {
                    Position p = q.poll();
                    for (int[] d : dirs) {
                        int nx = p.x + d[0], ny = p.y + d[1];
                        if (nx >= m || nx < 0 || ny >= n || ny < 0) {
                            continue;
                        }
                        if (grid[nx][ny] == 0 && !vis[nx][ny][p.count]) {
                            if (nx == m - 1 && ny == n - 1) {
                                return steps;
                            }
                            q.offer(new Position(nx, ny, p.count));
                            vis[nx][ny][p.count] = true;
                        } else if (grid[nx][ny] == 1 && p.count > 0 && !vis[nx][ny][p.count - 1]) {
                            q.offer(new Position(nx, ny, p.count - 1));
                            vis[nx][ny][p.count - 1] = true;
                        }

                    }
                }
            }
            return -1;
        }

        class Position {
            int x, y;
            int count;//当前状态下还可以经过多少个障碍物,此数量为非负

            public Position(int x, int y, int count) {
                this.x = x;
                this.y = y;
                this.count = count;
            }
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值