LeetCode 994. 腐烂的橘子

时间:2020-03-10
本文章向大家介绍 LeetCode 994. 腐烂的橘子,主要包括 LeetCode 994. 腐烂的橘子使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

LeetCode 994. 腐烂的橘子

题目

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

值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,任何与腐烂的橘子(在 4 个正方向上)相邻的新鲜橘子都会腐烂。

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

示例 1:

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

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

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

提示:

1 <= grid.length <= 10
1 <= grid[0].length <= 10
grid[i][j] 仅为 0、1 或 2

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotting-oranges
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

思路1-BFS,广度优先,使用优先队列

  1. 先统计一遍所有的好坏橘子数量,若有任意一种为0,可快速返回;
  2. 初始坏橘子入队列,然后每次取完队列里的所有坏橘子并尝试感染附近的橘子,感染到一个就减去一个好橘子数量并把感染到的橘子加入队列,但是这是下一轮的扩散橘子,跟本轮的要分开这里要注意,每轮只要有感染到就加一分钟,直到最后一轮无橘子可感染;
  3. 最后检查好橘子还有没有再返回对应结果;

思路2-DFS,深度优先,使用递归给坏橘子加一个腐败值的概念,求最大腐败值即可

  1. 第一次遍历遇到坏橘子就开始DFS,并用一个boolean记录;
  2. 初始坏橘子不断向四周扩散,且中途忽略腐败值小于其自身的值(DFS剪枝),如此递归;
  3. 最后一次遍历,若还有好橘子直接返回,若第一次的boolean为false,则返回0,否则返回最大腐败值-2;

总结:BFS是使用队列/优先队列去解决,而DFS是使用栈/递归去解决问题

package leetcode;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * @author ZhouJie
 * @date 2020年3月4日 下午2:37:58 
 * @Description: 994. 腐烂的橘子
 *
 */
public class LeetCode_0994 {

}

class Solution_0994 {
    /**
     * @author: ZhouJie
     * @date: 2020年3月4日 下午5:22:38 
     * @param: @param grid
     * @param: @return
     * @return: int
     * @Description: 1-BFS;
     *
     */
    public int orangesRotting_1(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int goodG = 0;
        Deque<int[]> deque = new ArrayDeque<int[]>();
        for (int i = 0; i < m; i++) {
            // 统计好橘子的数量
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    goodG++;
                    // 坏橘子入队列
                } else if (grid[i][j] == 2) {
                    deque.offer(new int[] { i, j });
                }
            }
        }
        // 若没有好橘子或没有坏橘子,直接返回
        if (goodG == 0) {
            return 0;
        }
        if (goodG > 0 && deque.isEmpty()) {
            return -1;
        }
        // 上下左右的传播方向
        int[] d1 = new int[] { 1, -1, 0, 0 };
        int[] d2 = new int[] { 0, 0, 1, -1 };
        int minute = 0, badG;
        while (!deque.isEmpty()) {
            badG = deque.size();
            while (badG-- > 0) {
                int[] bad = deque.poll();
                for (int i = 0; i < 4; i++) {
                    int x = bad[0] + d1[i];
                    int y = bad[1] + d2[i];
                    if (x > -1 && x < m && y > -1 && y < n && grid[x][y] == 1) {
                        deque.offer(new int[] { x, y });
                        grid[x][y] = 2;
                        goodG--;
                    }
                }
            }
            minute++;
        }
        return goodG == 0 ? minute - 1 : -1;
    }

    /**
     * @author: ZhouJie
     * @date: 2020年3月4日 下午5:22:58 
     * @param: @param grid
     * @param: @return
     * @return: int
     * @Description: 2-DFS;
     *
     */
    public int orangesRotting_2(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        // 记录是否有坏橘子
        boolean bad = false;
        // 第一次遍历,遇到坏橘子直接dfs,并且每次增加腐烂值val(初始值2),则最终的耗时为Max(val)-2
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 2) {
                    bad = true;
                    dfs(grid, i, j, 2);
                }
            }
        }
        int maxBad = 2;
        // 第二次遍历检查是否还有好橘子,有则直接返回-1
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                int k = grid[i][j];
                if (k == 1) {
                    return -1;
                }
                maxBad = Math.max(maxBad, k);
            }
        }
        // 如果没有好橘子,则检查初始是否有坏橘子,没有则为0,有则返回max(val)-2
        return !bad ? 0 : maxBad - 2;
    }

    /**
     * @author: ZhouJie
     * @date: 2020年3月4日 下午6:13:29 
     * @param: @param grid
     * @param: @param x
     * @param: @param y
     * @param: @param val
     * @return: void
     * @Description: DFS核心
     *
     */
    private void dfs(int[][] grid, int x, int y, int val) {
        // 边界检测
        if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length) {
            return;
            // 腐败值小于当前最大值的不再扩散,即DFS的剪枝
        } else if (grid[x][y] != 1 && grid[x][y] < val) {
            return;
        } else {
            // 符合要求的继续扩散
            grid[x][y] = val;
            val++;
            dfs(grid, x - 1, y, val);
            dfs(grid, x + 1, y, val);
            dfs(grid, x, y - 1, val);
            dfs(grid, x, y + 1, val);
        }
    }
}

原文地址:https://www.cnblogs.com/izhoujie/p/12456998.html