news 2026/9/16 21:28:12

BFS算法解析:LeetCode 994腐烂的橘子问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
BFS算法解析:LeetCode 994腐烂的橘子问题

1. 问题背景与题目解析

今天想和大家分享一道经典的广度优先搜索(BFS)算法题——LeetCode 994题"腐烂的橘子"。这道题看似简单,但蕴含着很多值得深入思考的算法细节,也是面试中的高频题目。

题目描述是这样的:在一个给定的网格中,每个单元格可以有以下三个值之一:

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

每分钟,任何与腐烂橘子相邻(上下左右)的新鲜橘子都会腐烂。我们需要计算直到没有新鲜橘子可以被腐烂为止所需的最小分钟数。如果不可能使所有新鲜橘子都腐烂,则返回-1。

2. 解题思路分析

2.1 问题建模

这道题本质上是一个典型的图论中的多源点广度优先搜索问题。我们可以将网格看作一个图:

  • 每个橘子(值为1或2的单元格)是图中的一个节点
  • 相邻的橘子之间存在边
  • 腐烂过程就是从多个源点(初始腐烂的橘子)开始,向外扩散感染的过程

2.2 算法选择

为什么选择BFS而不是DFS?

  1. BFS天然适合计算最短路径/最小时间的问题
  2. 多个腐烂橘子同时影响周围橘子,这符合BFS的层级遍历特性
  3. DFS可能会造成重复计算和不必要的时间浪费

2.3 关键变量设计

我们需要维护几个关键变量:

  • 新鲜橘子的计数(用于判断最终是否全部腐烂)
  • 当前腐烂橘子的队列(用于BFS遍历)
  • 时间计数器(记录传播的分钟数)

3. 详细实现步骤

3.1 初始化阶段

def orangesRotting(grid): rows = len(grid) if rows == 0: return -1 cols = len(grid[0]) fresh = 0 queue = [] # 初始化:统计新鲜橘子数量,记录所有腐烂橘子的位置 for r in range(rows): for c in range(cols): if grid[r][c] == 1: fresh += 1 elif grid[r][c] == 2: queue.append((r, c))

3.2 BFS处理阶段

minutes = 0 directions = [(-1,0), (1,0), (0,-1), (0,1)] # 上下左右四个方向 while queue and fresh > 0: minutes += 1 # 处理当前分钟的所有腐烂橘子 for _ in range(len(queue)): r, c = queue.pop(0) for dr, dc in directions: nr, nc = r + dr, c + dc if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == 1: grid[nr][nc] = 2 fresh -= 1 queue.append((nr, nc))

3.3 结果判断阶段

return minutes if fresh == 0 else -1

4. 复杂度分析与优化

4.1 时间复杂度

  • 最坏情况下需要遍历整个网格:O(m×n)
  • 每个橘子最多被处理一次:O(m×n)
  • 总时间复杂度:O(m×n)

4.2 空间复杂度

  • 队列最多存储所有腐烂橘子:O(m×n)
  • 实际最坏情况下可能达到网格大小

4.3 优化思路

  1. 可以提前终止的条件:

    • 初始时没有新鲜橘子,直接返回0
    • 初始时没有腐烂橘子但有新鲜橘子,直接返回-1
  2. 使用双端队列(deque)代替list可以提高pop(0)的效率

5. 边界条件与测试用例

5.1 常见边界情况

  1. 空网格:返回-1
  2. 没有新鲜橘子:返回0
  3. 没有腐烂橘子但有新鲜橘子:返回-1
  4. 新鲜橘子无法被全部感染:返回-1

5.2 测试用例示例

测试用例1: [[2,1,1],[1,1,0],[0,1,1]] 预期输出:4 测试用例2: [[2,1,1],[0,1,1],[1,0,1]] 预期输出:-1 测试用例3: [[0,2]] 预期输出:0

6. 常见错误与调试技巧

6.1 常见错误

  1. 忘记处理初始没有新鲜橘子的情况
  2. 分钟数计算错误(特别是初始分钟应该是0)
  3. 没有正确处理多个腐烂橘子同时扩散的情况
  4. 边界检查不完整导致数组越界

6.2 调试技巧

  1. 打印每分钟后的网格状态
  2. 跟踪新鲜橘子数量的变化
  3. 检查队列处理是否正确(特别是层级处理)

7. 算法扩展思考

7.1 变种问题

  1. 如果橘子腐烂的速度不同(比如有些需要2分钟才能腐烂相邻橘子)?
  2. 如果橘子可以斜对角传播?
  3. 如果网格非常大,如何优化内存使用?

7.2 实际应用场景

  1. 疫情传播模型
  2. 森林火灾蔓延模拟
  3. 计算机网络中的病毒传播

8. 个人实现心得

在实际编码中,我发现有几个关键点特别容易出错:

  1. 分钟数的增加时机:应该在处理完当前所有腐烂橘子后再增加,而不是每次处理一个邻居就增加。

  2. 新鲜橘子的计数:必须在将橘子标记为腐烂时就减少计数,而不是在处理队列时才计数。

  3. 层级处理:使用for _ in range(len(queue))的技巧来确保正确处理每分钟的层级关系。

这道题很好地展示了BFS在多源点最短路径问题中的应用,也提醒我们在处理网格类问题时要注意边界条件和状态更新的时机。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 21:27:32

AD9653与FPGA高速连接设计:JESD204B接口、时钟树与PCB信号完整性

1. 项目概述&#xff1a;这不是接根线就完事的“简单连接”AD9653采集模块怎样连接FPGA底板&#xff1f;——看到这个标题&#xff0c;我第一反应不是去翻数据手册&#xff0c;而是先问自己&#xff1a;你手里的FPGA底板&#xff0c;是实验室里那块带JTAG下载口、几个LED和按键…

作者头像 李华
网站建设 2026/9/16 21:23:10

2026年有线耳机选购指南:从单元到参数,避开这些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/16 21:22:13

DGX Spark实战:从大模型微调到边缘推理的完整指南

第一次把 DGX Spark 放到办公桌上的时候&#xff0c;我盯着这个比 Mac mini 大不了多少的机箱看了半天。说明书上写着 1 PFLOP&#xff08;FP4&#xff09;AI 算力、128GB 统一内存&#xff0c;NVIDIA 管它叫“个人 AI 超级计算机”。我习惯性打开终端敲下nvidia-smi&#xff0…

作者头像 李华
网站建设 2026/9/16 21:21:38

NVIDIA DGX Spark实战指南:从驱动到大模型微调推理

NVIDIA DGX Spark 是我今年上手之后&#xff0c;实际用下来最意外的一台设备。体积比 Mac mini 大不了多少&#xff0c;却能同时承接大模型训练、微调、部署和边缘推理整条链路&#xff0c;而且开发者体验比传统 GPU 服务器顺畅太多。这篇指南我不打算只念官方参数&#xff0c;…

作者头像 李华
网站建设 2026/9/16 21:20:42

Windows Server DNS正向与反向解析配置:从A记录到PTR记录全流程

Windows环境里的DNS服务&#xff0c;我一直觉得正向解析和反向解析是最容易让人绕晕、却又绕不过去的两块内容。很多刚接触Windows Server的朋友&#xff0c;搭完DNS后只会建几条A记录&#xff0c;等到邮件服务器被对方退信、日志分析里全是IP地址的时候&#xff0c;才想起来反…

作者头像 李华
网站建设 2026/9/16 21:19:51

网络可视媒体智能计算:从模型训练到端侧部署的完整实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华