腐烂的橘子
题目链接
https://leetcode-cn.com/problems/rotting-oranges/
思路:
很典型的BFS,就是不断生成新的状态结点,然后找到直接return(最短/最小)
但是注意了,这个题目可能不只一个烂橘子,也就是可能是由多个点进行bfs
=> 单源广度优先搜索
=> 多源广度优先搜索
package 每日一题;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
/*
在给定的网格中,每个单元格可以有以下三个值之一:
值 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. 1 <= grid.length <= 10
2. 1 <= grid[0].length <= 10
3. grid[i][j] 仅为 0、1 或 2
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotting-oranges
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class code01_腐烂的橘子 {
int R;
int C;
boolean[][] vis;
int[] dr = new int[] { -1, 0, 1, 0 };
int[] dc = new int[] { 0, -1, 0, 1 };
public void print(int[][] grid) {
for (int[] arr : grid) {
System.out.println(Arrays.toString(arr));
}
System.out.println("===================");
}
public boolean in(int r, int c) {
return 0 <= r && r < R && 0 <= c && c < C;
}
public boolean checkOK(int[][] grid) {
for (int i = 0; i < R; i += 1) {
for (int j = 0; j < C; j += 1) {
if (grid[i][j] == 1) {
return false;
}
}
}
return true;
}
// 检查是否有新鲜橘子
public boolean checkGood(int[][] grid) {
for (int r = 0; r < R; r += 1) {
for (int c = 0; c < C; c += 1) {
if (grid[r][c] == 1) {
return true;
}
}
}
return false;
}
public int orangesRotting(int[][] grid) {
R = grid.length;
C = grid[0].length;
// 最大就是 10 * 10
vis = new boolean[10][10];
Queue<Node> q = new LinkedList<Node>();
// depth: 存放对应深度和步数的
// key: 当前层数 value: 最少的步数
Map<Integer, Integer> depth = new HashMap<Integer, Integer>();
if (!checkGood(grid)) { // 如果没有新鲜橘子的话,直接return 0
return 0;
}
for (int r = 0; r < R; r += 1) {
for (int c = 0; c < C; c += 1) {
if (grid[r][c] == 2) {
// 把坏橘子都加入,作为第0层
// 其实多源BFS只是把第0层加为多个
vis[r][c] = true;
// 把二维数组的下标转换为一个唯一值
int code = r * C + c;
depth.put(code, 0);
q.offer(new Node(0, r, c));
}
}
}
int ans = 0;
while (!q.isEmpty()) {
// 这是多源不一样的地方,之前都是取一个,现在是取一层
int len = q.size();
for (int i = 0; i < len; i += 1) { // 按层次来
Node now = q.poll();
for (int j = 0; j < 4; j += 1) {
int tr = now.r + dr[j];
int tc = now.c + dc[j];
// 判断是否越界和判断是否访问过
// 而且被污染的一定要是新鲜的橘子
if (in(tr, tc) && !vis[tr][tc] && grid[tr][tc] == 1) {
vis[tr][tc] = true;
grid[tr][tc] = 2;
depth.put(tr * C + tc, depth.get(now.r * C + now.c)+1);
ans = depth.get(tr * C + tc);
q.offer(new Node(now.steps + 1, tr, tc));
}
}
}
// print(grid);
}
if(checkGood(grid)){ // 如果还有
return -1;
}
return ans;
}
class Node {
int steps; // 记录步数
int r, c; // 只需要记录需要修改的点,不用怎么地图都记录
public Node(int steps, int r, int c) {
super();
this.steps = steps;
this.r = r;
this.c = c;
}
}
public static void main(String[] args) {
// 测试代码
int[][] grid = { { 2, 1, 1 }, { 1, 1, 0 }, { 0, 1, 1 } };
// int[][] grid = { { 0, 2 } };
code01_腐烂的橘子 xx = new code01_腐烂的橘子();
System.out.println(xx.orangesRotting(grid));
}
}