图论——腐烂的橘子

题目:
在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:
值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。
返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1

这道题时典型的多源广度优先搜索(BFS)问题,因为一开始有多个腐烂的橘子,它们会同时向四周扩散腐烂,BFS非常适合这种逐层扩散的最小时间。

解题思路

  1. 初始化:遍历网络,统计新鲜橘子数量,并把所有初始腐烂橘子的坐标加入队列(多源起点)。
  2. BFS扩散:每分钟处理队列中当前所有腐烂橘子,让它们向上下左右四个方向腐烂新鲜橘子,每腐烂一个就更新队列和新鲜橘子数量。
  3. 统计时间:每完成一轮扩散,时间加1.
  4. 结果判断:遍历结束后,若还有新鲜橘子返回-1,否则返回总时间。

代码关键说明
队列作用:存储当前所有腐烂橘子的坐标,保证逐层扩散(每分钟处理一批)
方向数组:dirs快速遍历上下左右四个相邻单元格,简化代码。
时间计算:最后一轮新感染的橘子会留在队列里,队列非空会再进入一次while循环,导致time多计入了一次。
边界判断:必须检查坐标是否在网格范围内,防止数组越界。
提前返回:如果初始就没有新鲜橘子,直接返回0。

Queue 是队列:先进先出 FIFO

  • queue.poll() 👉 弹出、返回队头元素(最先进去的那个)
  • 绝对不是队尾

int size = queue.size() :
逐层扩散不是指数组的行,是指当前所有腐烂橘子同时扩散。

1. for (int[] dir : dirs) 是什么意思?

这叫增强for循环
作用:把dirs里的四个方向,一个一个拿出来

  • dirs是4个方向的集合
  • int[] dir表示:每次拿出一个方向(一维数组)

第一次循环:dir = {-1, 0}
第二次循环:dir = {1, 0}
第三次循环:dir = {0, -1}
第四次循环:dir = {0, 1}

2. dir[0] 和 dir[1] 是什么?
每个方向都是 两个数字:

所以:

  • dir [0] = 行怎么变
  • dir [1] = 列怎么变

3. nx = x + dir[0] 到底在干嘛?
(x, y) = 当前烂橘子的位置

加上方向偏移,就是新位置:
int nx = x + dir[0]; // 新的行号
int ny = y + dir[1]; // 新的列号

完整代码实现如下:
class Solution {

public int orangesRotting(int[][] grid) {

    Queue<int[]>queue = new LinkedList<>();
    int fresh = 0;

    int m = grid.length;
    int n = grid[0].length;

    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});
            }else if(grid[i][j]==1){
                fresh++;
            }
        }
    }

    if(fresh ==0) return 0;

    int[][] dirs = {{-1,0},{1,0},{0,-1},{0,1}};
    int time = 0;
   
   //进入扩散循环
    while(!queue.isEmpty()){
    //每层扩散结束后记录新的腐烂橘子个数,准备进入下一层的扩散
        int size = queue.size();
    //开始逐层扩散
        for(int i = 0;i<size;i++){
            //取出队列里第一个腐烂的橘子
            int cur[] = queue.poll();
            int x = cur[0];
            int y = cur[1];
    //将四个方向的新鲜橘子感染
        for(int[]dir:dirs){
            int nx = x + dir[0];
            int ny = y + dir[1];

            if(nx>=0&&nx<m&&ny>=0&&ny<n&&grid[nx][ny]==1){
                grid[nx][ny]=2;
                fresh--;
                queue.offer(new int[]{nx,ny});
            }
        }
     }
     //感染完一层,时间+1
        time++;
    }
    
  //扩散完成最后感染的腐烂橘子还留在队列里,会多进入一次while循环,多计入一次time,time-1才是答案
    return fresh==0?time-1:-1;
  //如果腐烂的橘子四周是空的,导致没有感染到新鲜橘子,fresh!=0;返回-1
}

}

posted @ 2026-04-25 22:38  AlexXuu  阅读(3)  评论(0)    收藏  举报