994. 腐烂的橘子

211 阅读2分钟

思路: 多源广度优先搜索

因为源头不是固定的,所以需要先将腐蚀源放到队列中,同时开始腐蚀。

//多源广度优先搜索
class Solution {
    public int orangesRotting(int[][] grid) {
        int m = grid.length, n = grid[0].length;

        // 烂橘子坐标 是 bfs起点
        Queue<int[]> queue = new LinkedList<>();
        // 好橘子数量
        int freshCount = 0;
        
        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) {
                    freshCount++; // 好橘子
                }
            }
        }

        int time = 0;

        // bfs条件 1.有烂橘子 2.有好橘子
        while (!queue.isEmpty() && freshCount > 0) {
            int size = queue.size();
            time++;

            for(int i = 0; i < size; i++) {
                int[] coord = queue.poll();
                int row = coord[0], col = coord[1];

                // 四个方向
                if (col + 1 < n && grid[row][col + 1] == 1) {
                    queue.offer(new int[]{row, col + 1});
                    grid[row][col + 1] = 2;
                    freshCount--;
                }

                if (col - 1 >= 0 && grid[row][col - 1] == 1) {
                    queue.offer(new int[]{row, col - 1});
                    grid[row][col - 1] = 2;
                    freshCount--;
                }

                if (row + 1 < m && grid[row + 1][col] == 1) {
                    queue.offer(new int[]{row + 1, col});
                    grid[row + 1][col] = 2;
                    freshCount--;
                }

                if (row - 1 >= 0 && grid[row - 1][col] == 1) {
                    queue.offer(new int[]{row - 1, col});
                    grid[row - 1][col] = 2;
                    freshCount--;
                }
            }
            
        }

        // 如果还有好橘子,说明无法腐蚀到,return -1
        return freshCount == 0 ? time : -1;

    }
}

encode 坐标:

class Solution {
    public int orangesRotting(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 2) {
                    queue.offer(i * n + j);
                    //需要先把腐烂的全部加到队列中,多源广度优先搜索
                    //万一一开始有多个腐烂的,可以同时开始腐蚀,ex:[[2,1,1],[1,1,1],[0,1,2]]
                    //如果按一个开始腐蚀,时间可能不对。
                }
            }
        }

        int time = 0;

        //hasFresh(grid)表示还有未被腐蚀的
        //!queue.isEmpty()表示还有烂橘子没腐蚀周边
        while (!queue.isEmpty() && hasFresh(grid)) {
            int size = queue.size();
            time++;
            for (int k = 0; k < size; k++) {
                int num = queue.poll();
                int curi = num / n, curj = num % n;
                if (curi + 1 < m && grid[curi + 1][curj] == 1) {
                    grid[curi + 1][curj] = 2;
                    queue.offer((curi + 1) * n + curj);
                }
                if (curi - 1 >= 0 && grid[curi - 1][curj] == 1) {
                    grid[curi - 1][curj] = 2;
                    queue.offer((curi - 1) * n + curj);
                }
                if (curj + 1 < n && grid[curi][curj + 1] == 1) {
                    grid[curi][curj + 1] = 2;
                    queue.offer(curi * n + curj + 1);
                }
                if (curj - 1 >= 0 && grid[curi][curj - 1] == 1) {
                    grid[curi][curj - 1] = 2;
                    queue.offer(curi * n + curj - 1);
                }
            }
        }
        //如果是腐蚀源执行完腐蚀操作,可能还有永远腐蚀不到的,这时候要返回-1
        if (hasFresh(grid)) {
            return -1;
        }
        return time;
    }
    //扫一遍,有新鲜橘子true, 无false
    public boolean hasFresh(int[][] grid) {
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 1) {
                    return true;
                }
            }
        }
        return false;
    }
}