994.腐烂的橘子

994.腐烂的橘子

在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:

值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。

返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1 。

示例 1:

994.腐烂的橘子

输入:grid = [[2,1,1],[1,1,0],[0,1,1]]
输出:4
示例 2:

输入:grid = [[2,1,1],[0,1,1],[1,0,1]]
输出:-1
解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个正向上。
示例 3:

输入:grid = [[0,2]]
输出:0
解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。

为什么用BFS
由题目可知每过一分钟腐烂的橘子周围的新鲜橘子也会腐烂掉,我们需要返回给定网格中的橘子多久会全部腐烂,如果不能全部腐烂则返回1,这种网格问题一开始肯定会想到DFS,即深度优先遍历,但是仔细想想,每个腐烂橘子每分钟都会腐烂周围的橘子,我们对一个腐烂橘子深度搜索没有任何意义,所以思路转变为BFS,即广度优先搜索,有了这一层想法后思路也很简单了,通常BFS应用在树结构上,用来求最短路径。

何为广度优先搜索
官解:所谓广度优先搜索,就是从起点出发,每次都尝试访问同一层的节点,如果同一层都访问完了,再访问下一层,最后广度优先搜索找到的路径就是从起点开始的最短合法路径。
通俗地讲:BFS 可以看成是层序遍历。从某个结点出发,BFS 首先遍历到距离为 1 的结点,然后是距离为 2、3、4…… 的结点。因此,BFS 可以用来求最短路径问题。BFS 先搜索到的结点,一定是距离最近的结点。

BFS思路
对于本题目,每分钟腐烂的橘子都会感染周围的新鲜橘子,被感染的橘子再过一分钟又会感染周围新鲜橘子,直到感染所以可以感染到的新鲜橘子,这过程就很像BFS嘛,实际上这道题在我眼里也是一个求最短路径的模型,腐烂橘子到所有新鲜橘子的最短路径,路径的长度就是最后的时间。
对于树我们可以从根节点开始逐层遍历,如果本题初始状态只有一个腐烂橘子的话也一样,但是可能有多个腐烂橘子,所以我们要用多源BFS,也很简单,先遍历一遍数组记录每个初始状态的腐烂橘子。

一般BFS都是通过队列实现的,把最开始的腐烂橘子的下标储存在一个队列中,然后逐个出队找腐烂橘子周围的新鲜橘子,感染它并且将它入队,用来感染下一层橘子,因为题目要求路径,所以我们需要通过一个变量来保存每一层入队的被感染橘子的数量,在遍历完一层后结果要加一,当腐烂橘子周围再也没有新鲜橘子时退出循环,然后再次遍历网格,如果还有新鲜橘子则返回-1,没有的话返回结果。

细节处理
这里有一个细节int res = -1;和return res == -1 ? 0 : res;,为什么结果初始化为-1呢,因为最开始所有腐烂橘子入队时res也要加一,如果没有新鲜橘子的话返回0,但是初始化化为0的话就会返回1,这不合理。对于初始化可以这么理解,最开始有一个超级细菌,在0时刻感染了最开始腐烂的橘子,我们要求的是这些橘子感染其他橘子的时间,所以初始化结果为-1了。但是还有一种情况是网格里一个腐烂橘子都没有,这样的话根本就不会进入循环,最后返回-1也不合理,所以当最后结果为-1时返回0即可,如何解释呢,如果超级细菌最开始没有感染橘子,那么0时刻(开始感染的时刻)和-1时刻(所有橘子都是新鲜的)将没有任何区别,但是时间依然流动了。
完整代码如下:
Ps:还可以优化,在这基础上加一个变量保存新鲜橘子的数量,就不需要最后再遍历一次数组了,只需要判断该变量是否为0即可。

class Solution {
    public int orangesRotting(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        Deque<int[]> queue = new LinkedList<>();  //队列实现BFS
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 2) {
                    queue.offer(new int[]{i, j});  //将最开始的腐烂橘子入队
                }
            }
        }
        int res = -1;
        while (!queue.isEmpty()) {  //还有可以被感染的橘子时循环
            int q = queue.size();  //该变量保存每一层橘子的个数
            res++;  //走完一层就+1
            for (int i = 0; i < q; i++) {  //循环遍历一层
                int[] temp = queue.poll();
                int r = temp[0];
                int c = temp[1];
                if (r - 1 >= 0 && grid[r - 1][c] == 1) {  //访问上边,如果不越界且为新鲜橘子则入队并且感染
                    queue.offer(new int[]{r - 1, c});
                    grid[r - 1][c] = 2;
                }
                if (r + 1 < m && grid[r + 1][c] == 1) {  //
                    queue.offer(new int[]{r + 1, c});
                    grid[r + 1][c] = 2;
                }
                if (c - 1 >= 0 && grid[r][c - 1] == 1) {  //
                    queue.offer(new int[]{r, c - 1});
                    grid[r][c - 1] = 2;
                }
                if (c + 1 < n && grid[r][c + 1] == 1) {  //
                    queue.offer(new int[]{r, c + 1});
                    grid[r][c + 1] = 2;
                }
            }
        }
        for (int i = 0; i < m; i++) {  //遍历最后的结果
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {  //如果还有新鲜橘子返回-1
                    return -1;
                }
            }
        }
        return res == -1 ? 0 : res;  //如果一开始没有腐烂橘子返回0,否则返回结果
    }
}

原文:https://leetcode.cn/problems/rotting-oranges/solution/by-nice-hermann9a2-tdws/

Original: https://www.cnblogs.com/liangren-na/p/16437624.html
Author: 良人呐
Title: 994.腐烂的橘子

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/619861/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • [Mysql]如何设置root密码(8.0+)

    在ubuntu上安装mysql时默认root账号是没有密码的,可以先用 mysql进入mysql,然后输入下面这个( mynewpassword改成要设置的密码): ALTER U…

    数据库 2023年6月16日
    0110
  • 项目管理构建工具——Maven(基础篇)

    项目管理构建工具——Maven(基础篇) 在前面的内容中我们学习了JDBC并且接触到了jar包概念 在后面我们的实际开发中会接触到很多jar包,jar包的导入需要到互联网上进行就会…

    数据库 2023年6月14日
    097
  • MySQL高可用架构-MMM、MHA、MGR、PXC、分库分表(补总结)

    404. 抱歉,您访问的资源不存在。 可能是URL不正确,或者对应的内容已经被删除,或者处于隐私状态。 [En] It may be that the URL is incorre…

    数据库 2023年5月24日
    0139
  • JVM-类加载

    JVM JAVA技术交流群:737698533 类加载 推荐视频 https://www.bilibili.com/video/BV1PJ411n7xZ JVM系列笔记结合此视频和…

    数据库 2023年6月16日
    0117
  • 容器化|在 S3 备份恢复 RadonDB MySQL 集群数据

    作者:程润科、钱芬视频:钱芬 上一篇文章我们演示了如何快速实现 MySQL 高可用集群部署,以及部署集群的校验和卸载方式。本文将演示如何对集群进行备份和恢复。 部署版本为 Rado…

    数据库 2023年5月24日
    0131
  • MySQL80下载安装/使用/连接报错

    @ * – 一、MySQL80下载 + 这里用社区版Community Server + 下载运行 * 仅Server Only安装就行 * 产品配置,click ne…

    数据库 2023年5月24日
    0145
  • StoneDB 为何敢称业界唯一开源的 MySQL 原生 HTAP 数据库

    时代在召唤: HTAP Is On The Way 近些年,HTAP 正在受到人们越来越多的关注,Gartner 在 2014 年提出了 HTAP 这个术语和它的定义: Hybri…

    数据库 2023年5月24日
    0110
  • Docker镜像操作

    Docker镜像操作 Docker 镜像是由文件系统叠加而成(是一种文件的存储形式)。最底端是一个文件引 导系统,即 bootfs,这很像典型的 Linux/Unix 的引导文件系…

    数据库 2023年6月14日
    0142
  • SQL函数-聚合函数

    聚合函数 聚合函数是对一组数据进行汇总输出的函数。 输入:一组数据集合输出:单个值 举例:返回一组数据的最大值、平均数、最小、方差等操作。 常见函数举例: 1,AVG函数:返回一组…

    数据库 2023年6月16日
    0115
  • 回溯问题学习总结

    回溯问题 三种情况 每种情况都有子集,组合,排列三种题型 无重复元素不可复选 //&#x5B50;&#x96C6;&#x95EE;&#x9898; …

    数据库 2023年6月16日
    0112
  • Graphics2D类

    Java语言在Graphics类提供绘制各种基本的几何图形的基础上,扩展Graphics类提供一个Graphics2D类,它拥用更强大的二维图形处理能力,提供、坐标转换、颜色管理以…

    数据库 2023年6月11日
    0110
  • dockerfile

    基本结构 Dockerfile 是一个文本格式的配置文件,用户可以使用 Dockerfile 快速创建自定义镜像。 Dockerfile 由一行行命令语句组成,并且支持以 # 开头…

    数据库 2023年6月14日
    0116
  • 商企网络拓扑的搭建

    前段时间因为工作项目需要模拟搭建客户环境的网络拓扑结构用于验证某款网关产品的功能, 因为不是专业的网管,对于计算机网络的实践也相对较少,所以在组件网络拓扑时遇到了不少的坑,做下记录…

    数据库 2023年6月6日
    0143
  • HackerRank第一趴–Basic Select

    ID number NAME VARCHAR2(17) COUNTRYCODE VARCHAR2(3) DISTRICT VARCHAR2(20) POPULATION numbe…

    数据库 2023年6月16日
    0124
  • POI操作EXCEL对象

    POI操作EXCEL对象HSSF:操作Excel 97(.xls)格式XSSF:操作Excel 2007 OOXML (.xlsx)格式,操作EXCEL内存占用高于HSSFSXSS…

    数据库 2023年6月16日
    0108
  • Redis缓存相关的几个问题

    1 缓存穿透 缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来…

    数据库 2023年6月14日
    0110
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球