LeetCode 热题 100_腐烂的橘子(52_994_中等_C++)(图;广度优先遍历(队列))

题目描述:

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

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

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

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

输入输出样例:

示例 1:
在这里插入图片描述

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

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

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

提示:
m== grid.length
n == grid[i].length
1 <= m, n <= 10
grid[i][j] 仅为 0、1 或 2

题解:

解题思路:

思路一(广度优先遍历(队列)):

1、从柿子腐烂的过程,可以容易的想到腐烂是从坏柿子为中心开始一圈一圈向外进行蔓延。每个柿子为一个腐烂的中心,同时进行腐烂。容易想到每个腐烂的橘子为中心同时进行广度优先遍历,将好柿子变为坏柿子。

2、具体思路如下:
① 一开始遍历整个网格,将所有腐烂的柿子入队(并统计好柿子的数量,如果好柿子的数量为0则返回时间0)。

② 统计此时队列中腐烂柿子的数量n0。
③ 将n0个腐烂柿子出队,并将其上下左右好柿子入队,入队时将其变为腐烂的柿子。
④ 此时将时间(time)+1,并更新剩余好柿子数量(好柿子-新腐烂的柿子)。

⑤ 统计此时队列中腐烂柿子的数量n1。
⑥ 将n1个腐烂柿子出队,并将其上下左右好柿子入队,入队时将其变为腐烂的柿子。
⑦ 此时将时间(time)+1,并更新剩余好柿子数量(好柿子-新腐烂的柿子)。



重复上述过程,直至队列为空为止。
⑧ 如果好柿子的数量>0,则输出-1。如果好柿子的数量=0,则输出时间(time)。

3、复杂度分析:
① 时间复杂度:O(mn),其中 n,m 分别为 grid 的行数与列数,先对网格的坏橘子入队,统计好橘子的数量O(mn)。再进行一次广度优先搜索的时间O(mn)。
② 空间复杂度:O(m+n),主要取决于栈的深度,最坏情况为m=n时,中心的一个为坏橘子,栈中元素最多为最外层的数量(2m+2n)。

代码实现

代码实现(思路一(广度优先遍历(队列))):
int orangesRotting(vector<vector<int>>& grid) {
    //网格的行和列
    int r_size=grid.size(),c_size=grid[0].size();
    //好柿子的数量
    int nums_goodOrange=0;
    //最小分钟数
    int time=0;
    //存放腐烂句子的队列
    queue<pair<int,int>> Q;

    //遍历网格统计好橘子的数量,并将坏橘子入队(进行后续的广度优先遍历)
    for (int r = 0; r < r_size; r++)
    {
        for (int c = 0; c < c_size; c++)
        {
            //坏柿子入队
            if (grid[r][c]==2)
            {
                Q.push({r,c});
            //统计好柿子数量
            }else if(grid[r][c]==1){
                nums_goodOrange+=1;
            }
        }
    }
    //如果好橘子的数量为0则之间返回0
    if (nums_goodOrange==0) return 0;

    //注意我们队列中一开始会存储坏橘子的数量,所以我们在这里加上,便于我们后续统计好橘子转换为坏橘子的数量
    nums_goodOrange+=Q.size();


    while (!Q.empty())
    {
        //“一层”坏橘子的数量
        int n=Q.size();
        //将n0个腐烂柿子出队,并将其上下左右好柿子入队,入队时将其变为腐烂的柿子
        //此时将时间(time)+1,并更新剩余好柿子数量(好柿子-新腐烂的柿子)。
        for (int i = 0; i < n; i++)
        {
            auto rc= Q.front();
            Q.pop();
            int r=rc.first,c=rc.second;

            //处理坏柿子紧挨着上下左右的好柿子
            if (r-1>=0 && grid[r-1][c]==1)
            {
                grid[r-1][c]=2;
                Q.push({r-1,c});
            }
            if (r+1<r_size && grid[r+1][c]==1)
            {
                grid[r+1][c]=2;
                Q.push({r+1,c});
            }
            if (c-1>=0 && grid[r][c-1]==1)
            {
                grid[r][c-1]=2;
                Q.push({r,c-1});
            }
            if (c+1<c_size && grid[r][c+1]==1)
            {
                grid[r][c+1]=2;
                Q.push({r,c+1});
            }
        }
        //新腐烂一层柿子后time+1,更新好柿子的数量
        ++time;
        nums_goodOrange-=n;
    }

    if (nums_goodOrange>0)
    {
        return -1;
    }
    //注意一开始我们统计了一次,最开始就是腐烂的坏柿子,所以要减去
    return time-1;
}
以思路一为例进行调试
#include<iostream>
#include <vector>
#include<queue>
using namespace std;

class Solution {
public:
    int orangesRotting(vector<vector<int>>& grid) {
        //网格的行和列
        int r_size=grid.size(),c_size=grid[0].size();
        //好柿子的数量
        int nums_goodOrange=0;
        //最小分钟数
        int time=0;
        //存放腐烂句子的队列
        queue<pair<int,int>> Q;

        //遍历网格统计好橘子的数量,并将坏橘子入队(进行后续的广度优先遍历)
        for (int r = 0; r < r_size; r++)
        {
            for (int c = 0; c < c_size; c++)
            {
                //坏柿子入队
                if (grid[r][c]==2)
                {
                    Q.push({r,c});
                //统计好柿子数量
                }else if(grid[r][c]==1){
                    nums_goodOrange+=1;
                }
            }
        }
        //如果好橘子的数量为0则之间返回0
        if (nums_goodOrange==0) return 0;

        //注意我们队列中一开始会存储坏橘子的数量,所以我们在这里加上,便于我们后续统计好橘子转换为坏橘子的数量
        nums_goodOrange+=Q.size();


        while (!Q.empty())
        {
            //“一层”坏橘子的数量
            int n=Q.size();
            //将n0个腐烂柿子出队,并将其上下左右好柿子入队,入队时将其变为腐烂的柿子
            //此时将时间(time)+1,并更新剩余好柿子数量(好柿子-新腐烂的柿子)。
            for (int i = 0; i < n; i++)
            {
                auto rc= Q.front();
                Q.pop();
                int r=rc.first,c=rc.second;

                //处理坏柿子紧挨着上下左右的好柿子
                if (r-1>=0 && grid[r-1][c]==1)
                {
                    grid[r-1][c]=2;
                    Q.push({r-1,c});
                }
                if (r+1<r_size && grid[r+1][c]==1)
                {
                    grid[r+1][c]=2;
                    Q.push({r+1,c});
                }
                if (c-1>=0 && grid[r][c-1]==1)
                {
                    grid[r][c-1]=2;
                    Q.push({r,c-1});
                }
                if (c+1<c_size && grid[r][c+1]==1)
                {
                    grid[r][c+1]=2;
                    Q.push({r,c+1});
                }
            }
            //新腐烂一层柿子后time+1,更新好柿子的数量
            ++time;
            nums_goodOrange-=n;
        }

        if (nums_goodOrange>0)
        {
            return -1;
        }
        //注意一开始我们统计了一次,最开始就是腐烂的坏柿子,所以要减去
        return time-1;
    }
};


int main(int argc, char const *argv[])
{
    vector<vector<int>> grid={{2,1,1},{0,1,1},{1,0,1}};
    //统计腐烂柿子的数量并输出
    Solution s;
    cout<<s.orangesRotting(grid);
    return 0;
}

部分代码解读

pair<int,int>的解读请点击此链接:(LeetCode 热题 100_岛屿数量(51_200_中等_C++)(图;深度优先遍历;广度优先搜索)(pair<int,int>)

LeetCode 热题 100_腐烂的橘子(52_994)原题链接
欢迎大家和我沟通交流(✿◠‿◠)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值