LeetCode-994-腐烂的橘子


题意描述:

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

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

每分钟,任何与腐烂的橘子(在 4 个正方向上)相邻的新鲜橘子都会腐烂。

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

提示:

  • 1 <= grid.length <= 10
  • 1 <= grid[0].length <= 10
  • grid[i][j] 仅为 0、1 或 2

示例:

一:
在这里插入图片描述

输入:[[2,1,1],[1,1,0],[0,1,1]]
输出:4

二:

输入:[[2,1,1],[0,1,1],[1,0,1]]
输出:-1
解释:左下角的橘子(第 2 行,  0 列)永远不会腐烂,因为腐烂只会发生在 4 个正向上。

三:

输入:[[0,2]]
输出:0
解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 

解题思路:

Alice: 这就是模拟题吗 ?
Bob: 可以当成模拟题去做。
Alice: 有点BFS的样子,用队列的话应该能减少重复计算的。
Bob: 对对。


代码:

Java 方法一: 模拟, 多次遍历二维数组。

class Solution {

    private int rotedCnt   = 0;
    private int orangeCnt  = 0;

    public int orangesRotting(int[][] grid) {
		
		// 统计共有多少橘子
        for(int i=0; i<grid.length; ++i){
            for(int j=0; j<grid[i].length; ++j){
                if(grid[i][j] > 0){
                    orangeCnt += 1;
                }
            }
        }
        //System.out.println("oranges " + orangeCnt);
		// rotting(grid) 返回这一分钟有多少橘子会腐败
        int minutes = 0;
        while(rotting(grid) > 0){
            minutes ++;
        }
        //System.out.println("minutes " + minutes);
        //System.out.println("rotedCnt " + rotedCnt);

		// 腐败过程结束,查看结果
        if(rotedCnt == orangeCnt){
            return minutes;
        }else{
            return -1;
        }
    }
    public int rotting(int[][] grid){

        int rottingCnt = 0;
        rotedCnt       = 0;
        // 这一秒钟腐败的
        int[][] directions = {{1,0},{-1,0},{0,1},{0,-1}};
        for(int i=0; i<grid.length; ++i){
            for(int j=0; j<grid[i].length; ++j){
                if(grid[i][j] == 2){
                    rotedCnt += 1;
                    for(int[] direction : directions){
                        int xx = i + direction[0];
                        int yy = j + direction[1];
                        if(xx >=0 && xx < grid.length && yy >= 0 && yy < grid[i].length && grid[xx][yy] == 1){
                            grid[xx][yy] = 3;  // 把这一分钟要腐败的先标记为 3 防止与之前已经腐败的混淆
                            rottingCnt ++;                  
                        }
                    }
                }
            }
        }
        for(int i=0; i<grid.length; ++i){
            for(int j=0; j<grid[i].length; ++j){
                if(grid[i][j] == 3){
                    grid[i][j] = 2;
                }
            }
        }
        // 这一分钟的腐败过程结束,标记重置为2
        return rottingCnt;
    }
}

Python 方法一:

class Solution:

    def orangesRotting(self, grid: List[List[int]]) -> int:

        # 统计橘子总数
        self.orangeCnt = 0
        for row in grid:
            for cell in row:
                if cell > 0:
                    self.orangeCnt += 1

        # 模拟腐烂过程
        self.rottedCnt = 0
        minute         = 0
        while self.helper(grid) > 0:
            minute += 1

        # 返回结果
        if self.orangeCnt == self.rottedCnt:
            return minute
        else:
            return -1 
        
    def helper(self, grid):

        self.rottedCnt = 0    # 置零,重新累加
        rotting        = 0    # 本次腐败的橘子数量 
        directions = [[1,0],[-1,0],[0,1],[0,-1]]
        for x in range(len(grid)):
            for y in range(len(grid[x])):
                if grid[x][y] == 2:
                    self.rottedCnt += 1
                    for direction in directions:
                        xx = x + direction[0]
                        yy = y + direction[1]
                        if xx >= 0 and xx < len(grid) and yy >= 0 and yy < len(grid[xx]) and grid[xx][yy] == 1:
                            grid[xx][yy]    = 3
                            rotting        += 1
        
        for x in range(len(grid)):
            for y in range(len(grid[x])):
                if grid[x][y] == 3:
                    grid[x][y] = 2
        
        return rotting

Python 方法二: 优化内存使用

class Solution:
    def orangesRotting(self, grid: List[List[int]]) -> int:

        self.orangeCnt = 0
        rotting        = []
        for x in range(len(grid)):
            for y in range(len(grid[x])):
                if grid[x][y] > 0:
                    self.orangeCnt += 1
                if grid[x][y] == 2:
                    rotting.append([x, y])

        self.rotted = 0
        minute      = 0
        rottingCnt, rotting = self.helper(grid, rotting)
        while rottingCnt > 0:
            minute += 1
            rottingCnt, rotting = self.helper(grid, rotting)
        
        if self.rotted == self.orangeCnt:
            return minute
        else:
            return -1
    
    def helper(self, grid, rotting):

        directions = [[1,0],[-1,0],[0,1],[0,-1]]
        rottingCnt = 0
        rottingOne = []
        for coor in rotting:
            self.rotted += 1
            for direction in directions:
                xx = coor[0] + direction[0]
                yy = coor[1] + direction[1]
                if xx>=0 and xx<len(grid) and yy>=0 and yy<len(grid[xx]) and grid[xx][yy] == 1:
                    rottingCnt += 1
                    grid[xx][yy] = 2
                    rottingOne.append([xx, yy])
        
        return rottingCnt, rottingOne

javascript 方法一:一种啰嗦的写法,没有吧腐烂的过程抽象出来,反而用 flag 数组来标记最新腐烂的橘子。

var orangesRotting = function (grid) {
  // 获取新鲜的橘子(data[i][j] === 1 的)个数
  const getOrangeLeftCnt = (data) => {
    let orangeCnt = 0;
    for (let i = 0; i < data.length; ++i) {
      for (let j = 0; j < data[i].length; ++j) {
        orangeCnt += data[i][j] === 1 ? 1 : 0;
      }
    }
    return orangeCnt;
  };
  // 判断坐标是否合法, 是否没有越界
  const isLegalCoord = (x, y, data) => {
    return x >= 0 && x < data.length && y >= 0 && y < data[0].length;
  };

  const reset = (data) => {
    for (let i = 0; i < data.length; ++i) {
      for (let j = 0; j < data[i].length; ++j) {
        data[i][j] = 0;
      }
    }
  };

  const gridCopy = JSON.parse(JSON.stringify(grid));
  const flag = JSON.parse(JSON.stringify(grid));
  reset(flag);
  const directions = [
    [0, 1],
    [0, -1],
    [-1, 0],
    [1, 0],
  ];
  let result = 0;
  let corrupt = 0;
  let newCorrupt = [];

  while (true) {
    corrupt = 0;
    for (let [xx, yy] of newCorrupt) {
      flag[xx][yy] = 0;
    }

    for (let i = 0; i < gridCopy.length; ++i) {
      for (let j = 0; j < gridCopy[i].length; ++j) {
        if (gridCopy[i][j] === 2 && flag[i][j] === 0) {
          // 烂橘子只能感染一次其他橘子
          flag[i][j] = 1;
          for (let dire of directions) {
            const xx = i + dire[0];
            const yy = j + dire[1];
            if (isLegalCoord(xx, yy, gridCopy) && gridCopy[xx][yy] === 1) {
              gridCopy[xx][yy] = 2;
              flag[xx][yy] = 1;
              newCorrupt.push([xx, yy]);
              corrupt += 1;
            }
          }
        }
      }
    }
    if (corrupt > 0) {
      result += 1;
    }
    if (corrupt === 0 || getOrangeLeftCnt(gridCopy) === 0) {
      break;
    }
  }
  result = getOrangeLeftCnt(gridCopy) === 0 ? result : -1;
  return result;
};

易错点:

  • 每一分钟只能 “BFS” 走一步,这一分钟即将腐烂的橘子不应该和上一分钟已经腐烂的橘子混淆,前者在这一分钟还不具备传播腐败的能力。

总结

在这里插入图片描述


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值