- 原题链接:994. 腐烂的橘子
题目
在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:
- 值 0 代表空单元格;
- 值 1 代表新鲜橘子;
- 值 2 代表腐烂的橘子。
每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。
返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1 。
示例 1:
输入:grid = [[2,1,1],[1,1,0],[0,1,1]]
输出:4
1 - 思路
通过 BFS 来实现
- 由于本题要处理的结点为 腐烂的橘子, 即从腐烂的橘子为出发点向 四周扩散:因此借助队列 Queue 来存储腐烂的橘子的个数
- 题目还需要判断是否所有 橘子都腐烂,所以还需一个 变量来统计正常橘子的个数。
- 因此 bfs 的 while 循环条件应该同时满足
**while (!queue.isEmpty() && freshCount > 0) **
2 - 题解
⭐腐烂的橘子 —— BFS 记忆点思路如下
public class Solution {
// 表示四个方向:右、下、左、上
private static final int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
public int orangesRotting(int[][] grid) {
int M = grid.length;
int N = grid[0].length;
Queue<int[]> queue = new LinkedList<>();
int freshCount = 0; // 新鲜橘子的数量
// 初始化队列,加入所有腐烂的橘子
for (int r = 0; r < M; r++) {
for (int c = 0; c < N; c++) {
if (grid[r][c] == 2) {
queue.offer(new int[]{r, c});
} else if (grid[r][c] == 1) {
freshCount++;
}
}
}
int round = 0; // 腐烂的轮数,或者分钟数
while (!queue.isEmpty() && freshCount > 0) {
int n = queue.size();
for (int i = 0; i < n; i++) {
int[] cur = queue.poll();
int curX = cur[0];
int curY = cur[1];
for (int[] d : dir) {
int nextX = curX + d[0];
int nextY = curY + d[1];
if (nextX >= 0 && nextX < M && nextY >= 0 && nextY < N && grid[nextX][nextY] == 1) {
grid[nextX][nextY] = 2; // 腐烂
freshCount--;
queue.offer(new int[]{nextX, nextY});
}
}
}
round++;
}
return freshCount == 0 ? round : -1;
}
}
🌀复杂度分析
时间复杂度
初始化部分
- 在初始化部分,代码遍历了整个grid矩阵一次,以计算新鲜橘子的数量并将腐烂的橘子的位置加入队列。这个遍历操作的时间复杂度是O(m*n),其中m是grid的行数,n是列数。这是因为每个元素都被访问了一次。
腐烂传播的循环部分
- 在这个部分,代码使用了一个队列来追踪每一轮中将要腐烂的橘子。对于队列中的每个橘子,代码检查其四个方向的邻居。在最坏的情况下,即整个grid最终都会被腐烂的橘子填满,每个橘子都会被放入队列中并被处理一次。每处理一个橘子,都会有最多4次邻居检查。
- 因此,腐烂传播的循环部分的时间复杂度也是O(m*n),因为每个格子最多被访问和加入队列一次(即使是新鲜橘子最终变成腐烂橘子后也只会被加入队列一次)。
空间复杂度
- 空间复杂度主要由队列的使用决定。在最坏的情况下,如果grid中的所有橘子都是腐烂的,那么它们都会被加入到队列中。因此,空间复杂度是O(m*n),这是因为在最坏的情况下,队列需要存储grid中所有位置的信息。
总结
- 时间复杂度:O(m*n),其中m是grid的行数,n是列数。
- 空间复杂度:O(m*n),主要是因为使用了队列来存储需要处理的橘子的位置。
3 - ACM 模式
public class hot51_rottingOrange {
public static int[][] dir = {{0,1},{1,0},{-1,0},{0,-1}};
public static int orangeRotting(int[][] grid) {
// 定义
int n = grid.length;
int m = grid[0].length;
Queue<int[]> queue = new LinkedList<>();
int fresh = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if(grid[i][j]==1){
fresh ++;
}else if(grid[i][j]==2){
queue.offer(new int[]{i,j});
}
}
}
int round = 0;
while(!queue.isEmpty() && fresh>0){
int len = queue.size();
for(int i = 0 ; i < len;i++){
int[] cur = queue.poll();
int curX = cur[0];
int curY = cur[1];
for(int j = 0 ; j <4;j++){
int nextX = curX + dir[i][0];
int nextY = curY + dir[i][1];
if(nextX>=0 && nextX<n && nextY>=0 && nextY<m && grid[nextX][nextY]==1){
grid[nextX][nextY] = 2;
queue.offer(new int[]{nextX,nextY});
fresh--;
}
}
}
round++;
}
return round;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("输入二维数组 行 row");
int row = sc.nextInt();
System.out.println("输入列数 col");
int col = sc.nextInt();
int[][] grid = new int[row][col];
for(int i = 0; i < row;i++){
for (int j = 0; j < col;j++){
grid[i][j] = sc.nextInt();
}
}
System.out.println("需要时间"+orangeRotting(grid));
}
}