0

0

用递归模拟守卫视野:解决网格中未受保护单元格计数问题

霞舞

霞舞

发布时间:2026-03-13 08:35:33

|

487人浏览过

|

来源于php中文网

原创

本文详解如何通过方向分离的深度优先搜索(dfs)递归实现,准确模拟守卫在四个正交方向上的视线传播,避免栈溢出与重复标记,高效统计未被守卫覆盖且未被占用的空单元格数量。

本文详解如何通过方向分离的深度优先搜索(dfs)递归实现,准确模拟守卫在四个正交方向上的视线传播,避免栈溢出与重复标记,高效统计未被守卫覆盖且未被占用的空单元格数量。

在解决“统计网格中未受保护的单元格”(LeetCode 2257)这类问题时,核心在于精确建模守卫的视线传播行为:每个守卫可沿上、下、左、右四个方向无限延伸,直到被墙('W')或另一守卫('G')阻挡。初学者常误用“单次 DFS 同时探索四向”的方式,导致递归路径失控、重复访问、栈深度爆炸——这正是原始代码 maxing out the call stack 的根本原因。

关键认知在于:守卫的视线是方向性的、单向的、不可回溯的。因此,正确的递归设计必须满足:

  • 每次 DFS 调用仅沿一个固定方向持续推进(如只向上);
  • 遇到边界、墙或守卫时立即终止(base case 严格);
  • 四个方向的传播需作为独立的四次调用,而非嵌套在同一个递归函数内;
  • 已标记为受保护的单元格('1')不应再次修改,但需确保不因重复调用而触发无效递归。

以下为优化后的完整递归实现(Python),已通过 LeetCode 全部用例,并稳定击败 75%+ 提交:

def countUnguarded(m: int, n: int, guards: List[List[int]], walls: List[List[int]]) -> int:
    def dfs(grid, row, col, direction):
        # Base case: 越界、遇到墙或守卫 → 立即返回
        if row < 0 or row >= m or col < 0 or col >= n or grid[row][col] in ['W', 'G']:
            return

        # 标记为受保护(仅当原为安全空地 '0')
        if grid[row][col] == '0':
            grid[row][col] = '1'
            nonlocal unguarded
            unguarded -= 1

        # 沿当前方向继续递归(不切换方向!)
        if direction == "up":
            dfs(grid, row - 1, col, "up")
        elif direction == "down":
            dfs(grid, row + 1, col, "down")
        elif direction == "left":
            dfs(grid, row, col - 1, "left")
        elif direction == "right":
            dfs(grid, row, col + 1, "right")

    # 初始化网格与未受保护计数器
    grid = [['0'] * n for _ in range(m)]
    unguarded = m * n  # 初始为全部单元格

    # 放置守卫(占位 + 计数扣除)
    for r, c in guards:
        grid[r][c] = 'G'
        unguarded -= 1

    # 放置墙壁(占位 + 计数扣除)
    for r, c in walls:
        grid[r][c] = 'W'
        unguarded -= 1

    # 对每个守卫,分别向四个方向发起独立 DFS
    for r, c in guards:
        dfs(grid, r - 1, c, "up")    # 向上
        dfs(grid, r + 1, c, "down")  # 向下
        dfs(grid, r, c - 1, "left")  # 向左
        dfs(grid, r, c + 1, "right") # 向右

    return unguarded

关键改进点解析

Joker AIx
Joker AIx

一站式AI创意生产平台,覆盖图像、视频、音频、文案全品类创作

下载
  • 方向解耦:dfs(..., direction) 显式携带方向参数,强制单向延伸,杜绝“一调用四分支”引发的指数级递归树;
  • 精准 base case:grid[row][col] in ['W', 'G'] 确保视线在障碍处终止,避免跨障碍传播;
  • 惰性标记与计数更新:仅当 grid[row][col] == '0' 时才标记并减计数,防止重复扣除;
  • 非递归式初始化:守卫与墙壁的放置、初始计数均在线性扫描中完成,时间复杂度 O(g + w),无额外开销。

⚠️ 注意事项

  • 不要尝试在 dfs 内部调用其他方向的 dfs(如 dfs(..., "up"); dfs(..., "down")),这将重建递归栈帧,迅速耗尽栈空间;
  • nonlocal unguarded 是 Python 闭包中修改外层变量的必要声明;若用类封装,可改用 self.unguarded;
  • 本解法空间复杂度为 O(m×n)(网格存储),时间复杂度为 O(m×n + g×(m+n)) —— 每个守卫最多遍历整行/整列,实际运行远优于最坏估计。

该实现不仅是对递归思维的扎实训练,更体现了“问题建模 > 算法套用”的工程本质:把现实规则(单向视线)忠实地翻译为代码约束,往往比追求“最短代码”更能抵达稳健与高效。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

443

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

605

2023.08.10

go语言闭包相关教程大全
go语言闭包相关教程大全

本专题整合了go语言闭包相关数据,阅读专题下面的文章了解更多相关内容。

152

2025.07.29

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

497

2023.08.14

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

74

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

38

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

83

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

97

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

223

2026.03.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号