尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

LeetCode 130题:被围绕区域的BFS与DFS解法详解

LeetCode 130题:被围绕区域的BFS与DFS解法详解
📅 发布时间:2026/8/3 11:54:01

1. 问题背景与核心挑战

LeetCode 130题"被围绕的区域"是矩阵遍历类问题的经典代表,要求将二维矩阵中被'X'完全包围的'O'区域全部替换为'X'。这个看似简单的问题实则暗藏多个算法考察点,尤其适合用来检验对广度优先搜索(BFS)和深度优先搜索(DFS)的理解深度。

问题的关键难点在于如何高效识别"被包围"的区域。直接遍历矩阵中心区域判断每个'O'是否被包围的方法时间复杂度高达O(n^4),完全不可行。经过分析可以发现:任何与边界相连的'O'区域都不可能被包围,这个逆向思维是解题的突破口。因此正确解法应该:

  1. 首先标记所有边界相连的'O'区域
  2. 然后遍历内部区域处理真正的被包围区域
  3. 最后恢复被标记的边界区域

这种"标记-处理-恢复"的三段式解法思路,将原本O(n^4)的时间复杂度优化到了O(n^2),是典型的空间换时间策略。下面我们具体看两种实现方式。

2. BFS解法详解

2.1 算法流程设计

广度优先搜索采用队列数据结构,按层遍历与边界'O'相连的所有区域。具体步骤:

  1. 初始化队列,将所有边界上的'O'坐标入队
  2. 创建相同大小的标记矩阵,记录需要保留的'O'
  3. 标准BFS循环:
    • 出队一个坐标
    • 检查四个方向的相邻格子
    • 如果是'O'且未被标记,则标记并入队
  4. 二次遍历矩阵:
    • 未被标记的'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)) # 步骤2:BFS标记 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 = r+dr, c+dc if 0<=nr<rows and 0<=nc<cols 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] = 'X'

2.2 复杂度分析与优化

时间复杂度:O(mn) - 每个节点最多入队一次 空间复杂度:O(mn) - 标记矩阵和队列的空间

实际编码时可以优化空间使用:

  1. 直接在原矩阵上标记,如将保留的'O'改为'T'
  2. 使用位运算压缩标记矩阵
  3. 对极大矩阵采用分块处理

关键技巧:在BFS中,将坐标(i,j)编码为i*cols+j可以提升缓存命中率,这对大规模矩阵能带来约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 (0<=r<rows and 0<=c<cols) or board[r][c] != 'O': return board[r][c] = 'T' # 临时标记 dfs(r+1, c) dfs(r-1, c) dfs(r, c+1) 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 0<=r<rows and 0<=c<cols and board[r][c] == 'O': board[r][c] = 'T' stack.append((r+1,c)) stack.append((r-1,c)) stack.append((r,c+1)) 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 'O'

3.2 性能实测对比

在LeetCode测试用例上的表现:

  • 递归DFS:平均92ms,最大递归深度min(m,n)
  • 迭代DFS:平均88ms,空间占用更稳定
  • BFS:平均85ms,适合广度较大的区域

实际工程中选择建议:对于规则网格,BFS通常表现更好;对于复杂拓扑结构,DFS可能更合适

4. 边界条件与特殊案例

4.1 必须处理的异常情况

  1. 空矩阵输入:直接返回
  2. 单行/单列矩阵:所有元素都是边界
  3. 全'X'矩阵:无需任何处理
  4. 全'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+),可以考虑:

  1. 将边界分区,每个线程处理一段边界
  2. 使用原子操作或锁保证标记正确性
  3. 最终合并结果

5.2 其他应用场景

类似的连通区域分析算法还可用于:

  1. 图像处理中的前景提取
  2. 棋盘类游戏的区域判定
  3. 地图导航中的可达区域计算
  4. 电路设计中的短路检测

6. 工程实践建议

  1. 预处理优化:先检查四个角点,如果都是'X'可以直接跳过对应行列的边界检查
  2. 内存布局:对于C++实现,按行优先存储矩阵可提升缓存命中率
  3. 多语言实现:Go语言的协程版本能获得更好的并发性能
  4. 调试技巧:在标记阶段打印中间矩阵状态,可视化检查标记过程

实际面试中,面试官可能会追问:

  • 如何证明你的算法是正确的?
  • 如果矩阵太大内存放不下怎么办?
  • 如何扩展到三维矩阵的情况?

这些问题的准备方向:

  1. 正确性证明:数学归纳法+边界条件覆盖
  2. 大矩阵处理:分块加载+多趟扫描
  3. 三维扩展:6方向遍历+空间分割树优化

相关新闻

  • 2026沈阳塑木围栏厂家哪家好、碳化木围栏厂家推荐:4个避坑要点+5条硬标准,帮你选对源头企业 - mobible
  • Windows 10/11 iPhone USB网络共享终极指南:3分钟免费安装苹果驱动
  • 青龙面板签到管理:30+平台自动化任务一站式解决方案

最新新闻

  • 2026年退货自己寄快递怎么便宜?资深行业人教你避开计费坑,大件行李也能省一半 - 快递物流资讯
  • 三步开启智能象棋时代:深度学习视觉识别让棋局分析零门槛
  • 2026 年至今,溆浦可靠的偏沟式雨水箅优质厂家怎么联系,暴雨天路上的积水居然能靠它解决?老司机都夸好用的这玩意儿你家附近有吗?-安行铸件 - 行业甄选官
  • 完整解决TranslucentTB开机启动失效问题的终极指南
  • 六层盲埋孔孔壁镀层、树脂塞孔、抗温振长效防护体系
  • 新都女士假发怎么选?2026年口碑与定制趋势观察 - 优质品牌商家

日新闻

  • 112、LLC谐振变换器的输入电压瞬态仿真分析
  • 2026深圳疑难签证办理指南:拒签再签/商务签/高端定制机构怎么选 - 互联网科技品牌测评
  • C-LODOP在Edge等现代浏览器中的部署、适配与实战应用

周新闻

  • 怀化母婴除甲醛公司测甲醛中心怎么选:康之居母婴除甲醛标准、流程、避坑指南 - 信誉隆金银铂奢回收
  • 三步打造你的终极音乐中心:foobox-cn网络电台功能完整指南
  • Lance湖仓格式:为多模态AI工作流设计的终极数据存储方案

月新闻

  • ClickHouse版本管理深度实战:4步构建零风险升级与回滚体系
  • Java 23 种设计模式:从踩坑到精通 | 番外:责任链模式 —— 物流审批流程实战
  • 华硕笔记本性能解放指南:G-Helper轻量级控制工具全面解析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号