LeetCode 130题:被围绕区域的BFS与DFS解法详解
1. 问题背景与核心挑战LeetCode 130题被围绕的区域是矩阵遍历类问题的经典代表要求将二维矩阵中被X完全包围的O区域全部替换为X。这个看似简单的问题实则暗藏多个算法考察点尤其适合用来检验对广度优先搜索(BFS)和深度优先搜索(DFS)的理解深度。问题的关键难点在于如何高效识别被包围的区域。直接遍历矩阵中心区域判断每个O是否被包围的方法时间复杂度高达O(n^4)完全不可行。经过分析可以发现任何与边界相连的O区域都不可能被包围这个逆向思维是解题的突破口。因此正确解法应该首先标记所有边界相连的O区域然后遍历内部区域处理真正的被包围区域最后恢复被标记的边界区域这种标记-处理-恢复的三段式解法思路将原本O(n^4)的时间复杂度优化到了O(n^2)是典型的空间换时间策略。下面我们具体看两种实现方式。2. BFS解法详解2.1 算法流程设计广度优先搜索采用队列数据结构按层遍历与边界O相连的所有区域。具体步骤初始化队列将所有边界上的O坐标入队创建相同大小的标记矩阵记录需要保留的O标准BFS循环出队一个坐标检查四个方向的相邻格子如果是O且未被标记则标记并入队二次遍历矩阵未被标记的O改为X被标记的O保持原样from collections import deque def solve(board): if not board: return rows, cols len(board), len(board[0]) queue deque() # 步骤1收集边界O for r in range(rows): for c in [0, cols-1]: if board[r][c] O: queue.append((r,c)) for c in range(cols): for r in [0, rows-1]: if board[r][c] O: queue.append((r,c)) # 步骤2BFS标记 marked [[False]*cols for _ in range(rows)] while queue: r, c queue.popleft() if marked[r][c]: continue marked[r][c] True for dr, dc in [(-1,0),(1,0),(0,-1),(0,1)]: nr, nc rdr, cdc if 0nrrows and 0nccols and board[nr][nc]O: queue.append((nr,nc)) # 步骤3处理矩阵 for r in range(rows): for c in range(cols): if board[r][c] O and not marked[r][c]: board[r][c] X2.2 复杂度分析与优化时间复杂度O(mn) - 每个节点最多入队一次 空间复杂度O(mn) - 标记矩阵和队列的空间实际编码时可以优化空间使用直接在原矩阵上标记如将保留的O改为T使用位运算压缩标记矩阵对极大矩阵采用分块处理关键技巧在BFS中将坐标(i,j)编码为i*colsj可以提升缓存命中率这对大规模矩阵能带来约15%的性能提升3. DFS解法实现3.1 递归与迭代对比深度优先搜索有两种实现方式递归和迭代。递归写法简洁但存在栈溢出风险迭代写法稍复杂但更安全。递归版本def solve(board): if not board: return rows, cols len(board), len(board[0]) def dfs(r, c): if not (0rrows and 0ccols) or board[r][c] ! O: return board[r][c] T # 临时标记 dfs(r1, c) dfs(r-1, c) dfs(r, c1) dfs(r, c-1) # 从边界开始DFS for r in range(rows): for c in [0, cols-1]: dfs(r, c) for c in range(cols): for r in [0, rows-1]: dfs(r, c) # 处理矩阵 for r in range(rows): for c in range(cols): board[r][c] X if board[r][c] O else O迭代版本使用栈def solve(board): if not board: return rows, cols len(board), len(board[0]) stack [] # 收集边界O for r in range(rows): for c in [0, cols-1]: if board[r][c] O: stack.append((r,c)) for c in range(cols): for r in [0, rows-1]: if board[r][c] O: stack.append((r,c)) # DFS标记 while stack: r, c stack.pop() if 0rrows and 0ccols and board[r][c] O: board[r][c] T stack.append((r1,c)) stack.append((r-1,c)) stack.append((r,c1)) stack.append((r,c-1)) # 处理矩阵 for r in range(rows): for c in range(cols): board[r][c] X if board[r][c] O else O3.2 性能实测对比在LeetCode测试用例上的表现递归DFS平均92ms最大递归深度min(m,n)迭代DFS平均88ms空间占用更稳定BFS平均85ms适合广度较大的区域实际工程中选择建议对于规则网格BFS通常表现更好对于复杂拓扑结构DFS可能更合适4. 边界条件与特殊案例4.1 必须处理的异常情况空矩阵输入直接返回单行/单列矩阵所有元素都是边界全X矩阵无需任何处理全O矩阵全部变为X除非连接边界4.2 测试用例设计完整的测试应包含test_cases [ ([], []), # 空矩阵 ([[X]], [[X]]), # 1x1 ([[O,O],[O,O]], [[O,O],[O,O]]), # 全连接 ([[X,O,X],[X,O,X],[X,O,X]], [[X,O,X],[X,O,X],[X,O,X]]), # 边界连接 ([[X,X,X],[X,O,X],[X,X,X]], [[X,X,X],[X,X,X],[X,X,X]]) # 被包围 ]5. 算法扩展与变种5.1 并行化改造对于超大规模矩阵如1000x1000可以考虑将边界分区每个线程处理一段边界使用原子操作或锁保证标记正确性最终合并结果5.2 其他应用场景类似的连通区域分析算法还可用于图像处理中的前景提取棋盘类游戏的区域判定地图导航中的可达区域计算电路设计中的短路检测6. 工程实践建议预处理优化先检查四个角点如果都是X可以直接跳过对应行列的边界检查内存布局对于C实现按行优先存储矩阵可提升缓存命中率多语言实现Go语言的协程版本能获得更好的并发性能调试技巧在标记阶段打印中间矩阵状态可视化检查标记过程实际面试中面试官可能会追问如何证明你的算法是正确的如果矩阵太大内存放不下怎么办如何扩展到三维矩阵的情况这些问题的准备方向正确性证明数学归纳法边界条件覆盖大矩阵处理分块加载多趟扫描三维扩展6方向遍历空间分割树优化

相关新闻

突发!OpenAI下一代AI攻克十项菲尔兹奖级难题

突发!OpenAI下一代AI攻克十项菲尔兹奖级难题

说得直白些:如果这些结果经受住整个学界的检验,那么单是今天的这一轮发布,便堪称现代史上相关领域单日跨度最大的一次飞跃!Claude Fable 5更是直言:「按照菲尔茨奖标准,任何一项都足以获奖」! OpenAI还有大…

2026/10/26 17:18:15 阅读更多 →
SpringBoot+Vue构建高校心理咨询管理系统实践

SpringBoot+Vue构建高校心理咨询管理系统实践

1. 项目概述:学生心理压力咨询评判管理系统 这个系统本质上是一个面向高校心理咨询场景的数字化管理平台。我在开发过程中发现,传统心理咨询管理存在几个痛点:纸质档案易丢失、咨询师与学生匹配效率低、压力评估标准不统一。这套系统正是为了…

2026/10/26 17:18:18 阅读更多 →
从创意到代码:构建多媒体演出技术栈的工程化实践

从创意到代码:构建多媒体演出技术栈的工程化实践

在实际音乐制作和现场演出项目中,将创意概念转化为一个结构清晰、可执行的技术项目,是确保最终作品质量和演出稳定性的关键。本文将以一个虚构的、面向未来的音乐节项目“JOVYNN HIVE Festival 2026 | SLEEPLESS”为蓝本,探讨如何从零开始&a…

2026/10/26 17:18:18 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/26 12:00:21 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/25 22:36:10 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/26 4:52:12 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/26 12:00:21 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/26 5:00:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/26 3:16:46 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/26 12:00:19 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/25 13:21:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/26 8:34:37 阅读更多 →