Leetcode6081. 到达角落需要移除障碍物的最小数目-----0-1BFS

题目表述

给你一个下标从 0 开始的二维整数数组 grid ,数组大小为 m x n 。每个单元格都是两个值之一:

  • 0 表示一个 空 单元格,
  • 1 表示一个可以移除的 障碍物 。
    你可以向上、下、左、右移动,从一个空单元格移动到另一个空单元格。

现在你需要从左上角 (0, 0) 移动到右下角 (m - 1, n - 1) ,返回需要移除的障碍物的 最小 数目。

示例:

输入:grid = [[0,1,1],[1,1,0],[1,1,0]]
输出:2
解释:可以移除位于 (0, 1) 和 (0, 2) 的障碍物来创建从 (0, 0) 到 (2, 2) 的路径。
可以证明我们至少需要移除两个障碍物,所以返回 2 。
注意,可能存在其他方式来移除 2 个障碍物,创建出可行的路径。

0-1广度优先搜索

常规的广度优先搜索可以找出在边权均为1时的单源最短路,然而在建模中,边权除了1之外也可能为0。
在常规的广度优先搜索中,我们使用队列作为维护节点的数据结构,就保证了从队列中取出的节点,它们与源点之间的距离是单调递增的。然而如果边权可能为0,就会出现如下的情况:

  • 源点s被取出队列;
  • 源点 s 到节点 v1 有一条权值为 11 的边,将节点 v1 加入队列;

  • 源点 s到节点 v2 有一条权值为 0 的边,将节点 v2 加入队列;

此时节点v2就会在节点v1之后被取出队列,但节点v2与原点之间的距离反而较小,这样就破坏了广度优先搜索正确性的基础。

可以使用双端队列代替普通的队列作为维护节点的数据结构,当任意节点u被取出队列时,如果它到某节点vi有一条权值为0的边,那么就将节点vi加入双端队列的队首,如果它到某节点vj有一条权值为1的边,那么和常规的bfs相同,将节点vj加入到双端队列的队尾。
0-1 广度优先搜索的实现其实与 Dijkstra 算法非常相似。在 Dijkstra 算法中,我们用优先队列保证了距离的单调递增性。而在 0-1 广度优先搜索中,实际上任意时刻队列中的节点与源点的距离均为 d 或 d+1(其中 d 为某一非负整数),并且所有与源点距离为 d 的节点都出现在队首附近,所有与源点距离为 d + 1 的节点都出现在队尾附近。因此,只要使用双端队列,对于边权为 0 和 1 的两种情况分别将对应节点添加至队首和队尾,就保证了距离的单调递增性。

class Solution { public int minimumObstacles(int[][] grid) { int m = grid.length; int n = grid[0].length; int[][] dis = new int[m][n]; for(int i = 0; i < m;i++){ Arrays.fill(dis[i], Integer.MAX_VALUE); } dis[0][0] = 0; int[][] dirs = {{1,0}, {-1, 0}, {0, -1}, {0,1}}; Deque<int[]> que = new ArrayDeque<>(); que.offer(new int[]{0,0}); while(!que.isEmpty()){ int[] cur = que.poll(); for(int[] dir : dirs){ int x = dir[0] + cur[0]; int y = dir[1] + cur[1]; if(x < 0 || y < 0 || x >= m || y >= n) continue; if(dis[cur[0]][cur[1]] + grid[x][y] < dis[x][y]){ dis[x][y] = dis[cur[0]][cur[1]] + grid[x][y]; if(grid[x][y] == 0) que.addFirst(new int[]{x,y}); else{ que.addLast(new int[]{x,y}); } } } } return dis[m-1][n-1]; } }

__EOF__

本文作者Younger
本文链接https://www.cnblogs.com/youngerwb/p/16342124.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   YoungerWb  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示