994. 腐烂的橘子(树/图的BFS问题)

解题思路:

多源BFS

,首选找到

所有的腐烂的橘子

,放入队列中,然后进行

BFS

广搜,广搜的

层数 - 1

就是所需要花费的分钟数。

在最开始先扫描一遍二维数组,将所有的

腐烂的橘子

加入

队列

,同时统计新鲜橘子的数量

freshCount

如果扫描完毕发现没有找到

腐烂的橘子

,则此时可以直接确定答案:若

freshCount>0

则答案为

-1

(不可能全部腐烂),否则答案为

0

(即 

分钟时就没有新鲜的橘子了)。

如果有找到

腐烂的橘子

,则进行

按层

BFS

,每次取出队列的大小,访问这一层的每个腐烂的橘子,

在每一层中,查看腐烂橘子的四个方向的邻居,如果

邻居未越界且

是新鲜的橘子,就将其腐烂,并入队,同时将

freshCount - 1

在访问完一层后,层索引 level++。

最终看

freshCount

是否还有剩余,如果还有

剩余,

说明还存在新鲜橘子,答案为

-1

(没能全部腐烂)

,否则答案为 

level - 1

(

最后一层会腐烂0个橘子

) 。

在第 5 次 BFS 中会腐烂 0 个橘子,然后退出BFS的循环,上图没有画出(注:第 4 次 BFS 中会将上图中最后一个橙黄色的 2 入队,进入第 5 次 BFS 时,会取出这个 2 然后发现它周围没有橘子可腐烂了,此时退出整个BFS)。所以总共会执行 5 层BFS搜索,但只需要 4 分钟即可全部腐烂完毕。因此答案是 level - 1。

542. 01 矩阵(树/图的BFS问题)

解题思路:

1.

多源BFS

,类似994.腐烂的橘子,对于矩阵中的每一个元素,如果是

0

,那么离它最近的

0

就是它自己,因此

0

的位置距离是

0

因此可以

从所有的 0 开始出发进行 BFS,寻找未访问过的 1

,并将该位置的

距离

设置为当前

BFS的层数

首先遍历一遍矩阵将遇到的 

全部入队,并标记已访问,然后只要队列不为空,就取出当前队列大小,访问这一层的节点,

每次取出当前队首的位置,访问它的上下左右四个邻居,如果邻居未访问过且没有越界,就将邻居坐标入队并标记已访问,同时设置邻居的距离值,

到邻居的距离值就是当前搜索的层数

注意:标记是否已访问可以使用

boolean[][] visited

数组,也可以在原矩阵上修改,初始时将所有的

1

改成

-1

为什么需要

从 0 出发广搜 1

,而不是从 1 出发去广搜 0?

首先矩阵中两个数字之间距离是相互等价的:从 1 到 0 的距离就是从 0 到 1 的距离。

假设10000x10000的矩阵中只有一个0,那么如果从1出发去广搜0的话,需要对剩余所有的1都进行一遍BFS来更新到这个0的距离,也就是需要进行

99,999,999

次BFS。

但是如果我们从这个0出发去广搜1的话,只需要进行

1

次BFS即可知道这个0到每个1的距离(也就是每个1到这个0的距离)。

当矩阵中有很多个0的时候,我们可以把这些 0 看成一个整体的「超级零」,它与矩阵中所有的 0 相连,这样的话,就与矩阵中只有一个 0 的情况一样了,那么怎样才能做到看成一个整体的「超级零」呢?开始就提前把所有的 0 全部加入队列,然后再开始 BFS,这就相当于从这个整体的「超级零」出发向外进行一圈一圈的BFS搜索。

 

这题代码结构几乎与994. 腐烂的橘子一样,注意两点:

更新答案的时机是在 BFS 搜索将邻居入队的时候,更新的是邻居格子的答案(邻居是值为1的格子)。

需要将统计层数的代码level++放在每一层访问的开头,因为访问该层的邻居节点时就需要使用到层数了,所以需要提前统计。

下面是使用提前将矩阵中的 1 置为 -1 的方式来代替 visited 数组的版本: 

因为矩阵中除了 0 就是 1,将所有的 1 置为 -1 后,只需判断遇到的格子只要是 -1 就表示是未访问过的,将该格子的值更新为当前搜索的层数 level 即可。

解题思路:

2.

动态规划

,我们用

dp[i][j]

来表示该位置距离最近的

0

的距离。对于任一点

(i, j)

,距离

0

的距离为:

if matrix[i][j] == 1,f(i, j) = 1 + min(dp(i - 1, j), dp(i, j - 1), dp(i + 1, j), dp(i, j + 1))  

if matrix[i][j] == 0,dp(i, j) = 0                                                    

我们发现

dp[i][j]

是由其

上下左右

四个状态来决定,无法从一个方向开始递推!

例如被四个

0

包围的 

1

,从中心位置的 

1

移动到这四个

0

,就需要使用四种不同的方法:

1) 只有

水平向左

移动 和

竖直向上

移动;

2) 只有

水平向左

移动 和

竖直向下

移动;

3) 只有

水平向右

移动 和

竖直向上

移动;

3) 只有

水平向右

移动 和

竖直向下

移动。

因此我们分别从四个角开始递推,就得到了位于

「左上方、右上方、左下方、右下方」

距离

(i,j)

的最近的 

0

的距离。

优化:从四个角开始的

4

次递推,还可以优化成从任一组对角开始的

2

次递推,比如只写从

左上角

右下角

开始递推就行了。

下面是从左上角开始扫描的流程示意:

为了方便处理for循环中的边界条件判断,我们可以在dp数组的上下左右各添加一行(防御编程思想),并初始化为最大值,

然后就可以省去各种条件判断,处理中间的部分的dp时,只需要考虑左上和右下的最小值+1即可:dp[i][j] = min(dp[i][j], min(左, 上) + 1)

 

或 dp[i][j] = min(dp[i][j], min(右, 下) + 1)

下面是从左上角开始扫描的流程示意:

此题dp解法较难想到。

1162. 地图分析(树/图的BFS问题)

解题思路:

1.

多源BFS

从陆地出发 向上下左右四周搜索海洋

,搜索的

最大

层数

就是离陆地最远的海洋距离。

首先遍历一遍矩阵,将所有遇到的

陆地

坐标

入队

。结束后判断如果队列大小为

0

,说明全是

海洋

,如果队列大小为

NxN

,说明全是

陆地

,这两种情况都返回

-1

然后从陆地开始进行

BFS

,每次取出当前队列大小,计数层数

level++

, 访问这一层的每个节点,每次取出队首元素坐标,然后看四周的邻居坐标,如果是海洋就入队并标记(或利用原数组置为

陆地

)。

最后返回BFS的

层数 - 1

,因为是从陆地出发的,

第一层是陆地

,所以层数要 - 1。(这跟腐烂的橘子求解答案一样)

这题跟542题非常相似,都是反向进行多源BFS,542是从所有的 0 出发找 1,这题是从所有的 1 出发找 0,要寻找的那一方就是题目要更新答案的那一方。

解题思路:

2.

动态规划

,代码跟542. 01 矩阵 dp解法类似,做两次dp,从左上到右下和从右下到左上。

先在dp数组的上下左右各添加一行,以处理边界问题࿰

相关文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。