LeetCodehot 力扣热题100 腐烂的橘子

代码注释与详细思路

这是一个求解“腐烂橙子”问题的解决方案,思路是通过模拟腐烂的过程来计算最小时间。问题的目标是找出腐烂橙子传染所有新鲜橙子的最短时间,或者在无法感染所有新鲜橙子的情况下返回 -1。

代码实现:

class Solution {

    // 方向数组,四个方向:右、下、上、左

    int Directions[4][2] = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};

public:

    int orangesRotting(vector<vector<int>>& grid) {

        int n = grid.size();   // 获取网格的行数

        int m = grid[0].size(); // 获取网格的列数

        int fresh = 0;          // 记录新鲜橙子的数量

        vector<pair<int, int>> q;  // 用来存储腐烂橙子的坐标

        

        // 遍历网格,统计新鲜橙子数并找到腐烂橙子的初始坐标

        for (int i = 0; i < n; i++) {

            for (int j = 0; j < m; j++) {

                if (grid[i][j] == 1) {  // 如果是新鲜橙子

                    fresh++;

                } else if (grid[i][j] == 2) {  // 如果是腐烂橙子

                    q.emplace_back(i, j);  // 将腐烂橙子位置加入队列

                }

            }

        }

        

        int ans = 0;  // 记录腐烂所需的时间

        // 当队列非空且还有新鲜橙子时,继续腐烂过程

        while (!q.empty() && fresh) {

            ans++;  // 每一轮腐烂处理后,时间增加1

            vector<pair<int, int>> new_q;  // 用来存储新一轮腐烂的橙子

            

            // 遍历当前队列中的所有腐烂橙子

            for (auto& [x, y] : q) {

                // 遍历四个方向:右、下、上、左

                for (auto& d : Directions) {

                    int i = d[0] + x;  // 计算新位置的行坐标

                    int j = d[1] + y;  // 计算新位置的列坐标

                    // 判断新位置是否在网格内并且是新鲜橙子

                    if (i >= 0 && j >= 0 && i < n && j < m && grid[i][j] == 1) {

                        fresh--;  // 新鲜橙子变腐烂

                        new_q.emplace_back(i, j);  // 加入新腐烂橙子的队列

                        grid[i][j] = 2;  // 更新为腐烂橙子

                    }

                }

            }

            

            q = move(new_q);  // 更新队列,继续处理下一轮

        }

        

        // 如果还有新鲜橙子未腐烂,返回 -1;否则返回最小时间

        return fresh ? -1 : ans;

    }

};

q = move(new_q); 会 覆盖 q 的资源。

具体情况:

• 在 q = move(new_q); 这一行中,std::move(new_q) 会将 new_q 的资源(即 new_q 中的元素)转移到 q 中。

• move 不会拷贝 new_q 中的元素,而是把 new_q 的内部资源(如指向内存的指针)转移给 q。

• 结果:q 将拥有 new_q 原本所拥有的资源,而 new_q 的资源就变得不可用(通常是一个空容器或者一个处于“空状态”的容器)。

覆盖的具体效果:

• q 会变成一个包含 new_q 元素的新容器,new_q 中的元素会被“移动”到 q。

• 原本属于 new_q 的资源(如内部动态数组、指针等)会被转移到 q,这意味着 q 将接管这些资源,而 new_q 不再拥有它们。

• new_q 会变成一个空容器,或者处于未定义状态(例如,某些容器的容量可能会发生变化,但它的元素将无法再被访问)。

小结:

• q = move(new_q); 会覆盖 q 的资源,使得 q 拥有 new_q 的元素,同时 new_q 的资源将被“转移”走,变为空容器或者不再使用原有数据。

• 这样做的好处是避免了不必要的拷贝操作,提高了性能。

详细思路:

1. 问题分析

• 我们有一个二维网格,其中有三种类型的格子:

• 0 表示空格

• 1 表示新鲜橙子

• 2 表示腐烂橙子

• 腐烂橙子会在 4 个方向上(上、下、左、右)将相邻的新鲜橙子感染成腐烂。每个腐烂橙子感染相邻的新鲜橙子需要 1 单位时间。

• 我们需要计算最少时间来让所有新鲜橙子都变成腐烂橙子。如果有任何新鲜橙子无法变腐烂,返回 -1。

2. 核心思路

• 使用广度优先搜索(BFS)模拟腐烂过程。腐烂的橙子将传播到其相邻的格子,逐步感染新鲜橙子。每一轮 BFS 执行都对应 1 单位时间。

• 初始状态是所有腐烂的橙子进入队列,每次 BFS 都扩展相邻的新鲜橙子。

3. 详细步骤

第一步:遍历网格,统计新鲜橙子数量并记录所有腐烂橙子的初始坐标。

第二步:使用队列存储腐烂橙子的坐标,进行广度优先搜索。在每一轮 BFS 中,腐烂的橙子会传播到周围的新鲜橙子。

第三步:每次 BFS 迭代结束后,时间增加 1,直到队列为空或者没有新鲜橙子可以腐烂。

第四步:如果有新鲜橙子未被腐烂,返回 -1;否则返回最小时间。

4. 运行步骤

• 初始化:计算网格的行列数,统计新鲜橙子的数量并找到腐烂橙子的初始位置。

• 使用 BFS 模拟腐烂过程,每轮遍历腐烂橙子的 4 个方向,感染相邻的新鲜橙子,直到没有新鲜橙子可以感染。

• 返回腐烂完成的最小时间,或者如果有新鲜橙子无法腐烂则返回 -1。

复杂度分析:

时间复杂度

• 假设网格的大小为 n * m,我们遍历整个网格两次:

1. 一次遍历用于统计新鲜橙子和腐烂橙子的初始状态(O(n * m))。

2. 一次 BFS 遍历,每个腐烂橙子最多会处理四个相邻的格子,因此时间复杂度是 O(n * m)。

• 总时间复杂度为 O(n * m)

空间复杂度

• 使用一个队列来存储腐烂橙子的坐标,最多存储所有腐烂橙子的位置,空间复杂度是 O(n * m)

示例:

输入:

vector<vector<int>> grid = {

    {2,1,1},

    {1,1,0},

    {0,1,1}

};

执行步骤:

1. 初始时,腐烂橙子的位置为 (0,0),新鲜橙子数量为 4。

2. 第 1 秒:(0,0) 腐烂橙子感染相邻的 (0,1) 和 (1,0)。

3. 第 2 秒:(0,1) 和 (1,0) 继续感染相邻的新鲜橙子。

4. 最终结果:所有新鲜橙子腐烂完毕,最小时间为 4 秒。

输出:

4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值