994.腐烂的橘子

🍊 994.腐烂的橘子

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

  • 0 代表空单元格;
  • 1 代表新鲜橘子;
  • 2 代表腐烂的橘子。

每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。

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

思路

基本思想

读完题之后,知道题目大致的流程是每一轮都是当前的橘子感染新的橘子,下一轮由新感染的橘子去继续感染得到更下一轮中的新感染橘子,相当于一个蔓延的过程,如果蔓延到最后,无法感染新橘子,还有新鲜橘子的话,返回-1,如果没有新鲜橘子的话,就返回感染了几轮

这样描述下来就是一个广度优先遍历的过程,也可以理解为树的层次遍历,但是树的层次遍历最开始只从一个根节点出发,这里相当于有多个"根节点",此时还是一样的逻辑,只是在"层次遍历之前",需要将所有的"根节点入队",增加了这样一步之后得到了多源广度优先遍历

需要注意的是,每次感染之后,需要将新鲜橘子的数量减一,并且这个新鲜橘子标记为被感染,入队之后下一轮从这些新感染的橘子出发进行蔓延

img

从图中可以看出,第一轮只蔓延了{[1,0],[0,1]}这两个橘子,第二轮从这两个新感染的橘子出发,感染了{[0,2],[1,1]}两个橘子,第三轮从这两个新感染的橘子出发,感染了{[2,1]}这个橘子,最后一轮感染了{[2,2]}这个橘子,至此所有的橘子都被感染完成,相当于没有新鲜橘子了,返回感染的轮次

执行流程

  1. 广度优先遍历之前增加一步,找到所有的"根节点"
  2. 按照广度优先遍历的方式,一层一层的遍历
  3. 统计遍历的层数
  4. 遍历到最后没有新鲜橘子或者无法感染新鲜橘子就返回结果

代码

根据以上描述,得出以下代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Solution {
    public int orangesRotting(int[][] grid) {
        LinkedList<int[]> queue=new LinkedList<>();
        int flesh=0;
        //找到所有"根节点"
        for(int i=0;i<grid.length;++i){
            for(int j=0;j<grid[0].length;++j){
                if(grid[i][j]==1)
                    ++flesh;
                if(grid[i][j]==2){
                    int[] temp=new int[2];
                    temp[0]=i;
                    temp[1]=j;
                    queue.addLast(temp);
                }
            }
        }
        int res=0;
        //广度优先遍历,查看多少层可以将橘子腐烂完
        while(flesh>0&&!queue.isEmpty()){
            ++res;
            int size=queue.size();
            //每次从一层出发
            for(int i=0;i<size;++i){
                int[] temp=queue.removeFirst();
                int x=temp[0];
                int y=temp[1];
                //腐烂上下左右的橘子,并且将腐烂后的橘子加入队列中
                if(x>0&&x<grid.length&&grid[x-1][y]==1){
                    int[] up={x-1,y};
                    grid[x-1][y]=2;
                    queue.addLast(up);
                    --flesh;
                }
                if(x>=0&&x<grid.length-1&&grid[x+1][y]==1){
                    int[] down={x+1,y};
                    grid[x+1][y]=2;
                    queue.addLast(down);
                    --flesh;
                }
                if(y>0&&y<grid[0].length&&grid[x][y-1]==1){
                    int[] left={x,y-1};
                    grid[x][y-1]=2;
                    queue.addLast(left);
                    --flesh;
                }
                if(y>=0&&y<grid[0].length-1&&grid[x][y+1]==1){
                    int[] right={x,y+1};
                    grid[x][y+1]=2;
                    queue.addLast(right);
                    --flesh;
                }
            }
        }

        //遍历完之后还有新鲜橘子就返回-1,否则返回res
        return flesh>0?-1:res;
    }
}

总结

主要是从广度优先遍历出发,得到了多源广度优先遍历的方法,仅仅是在广度优先遍历的方法之前增加了一步找到所有"根节点"的步骤