zoukankan      html  css  js  c++  java
  • LeetCode 994. 腐烂的橘子

    我的LeetCode:https://leetcode-cn.com/u/ituring/

    我的LeetCode刷题源码[GitHub]:https://github.com/izhoujie/Algorithmcii

    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);
    		}
    	}
    }
    
  • 相关阅读:
    Release和Debug的区别[转]
    SVM运用到多分类[引]
    HMM
    [转] 数据挖掘 机器学习 模式识别的关系
    [转]mysql 数据导入
    java 获取当前时间戳
    二叉树遍历建树[zhuan]
    关于c指针[转]
    词法分析
    组合数据类型练习,综合练习
  • 原文地址:https://www.cnblogs.com/izhoujie/p/12456998.html
Copyright © 2011-2022 走看看