跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

LeetCode 3661 可以被机器人摧毁的最大墙壁数目 - 离散化与线段树解法

综述由AI生成解析 LeetCode 3661 题,目标是在直线上计算机器人发射子弹可摧毁的最大墙壁数。机器人射程受限且会被其他机器人阻挡。文章分析了错误的线段树动态规划解法,指出重叠统计问题。随后提出正确的动态规划思路,结合线段树维护区间最大值,并利用坐标离散化处理大范围坐标导致的内存超限问题。最后提供了简化的 DP 版本及完整 C++ 代码实现,确保在时间和空间复杂度上满足要求。

RedisGeek发布于 2026/4/6更新于 2026/5/2225 浏览
LeetCode 3661 可以被机器人摧毁的最大墙壁数目 - 离散化与线段树解法

3661. 可以被机器人摧毁的最大墙壁数目

一条无限长的直线上分布着一些机器人和墙壁。给你整数数组 robots,distance 和 walls:

  • robots[i] 是第 i 个机器人的位置。
  • distance[i] 是第 i 个机器人的子弹可以行进的最大距离。
  • walls[j] 是第 j 堵墙的位置。

每个机器人有一颗子弹,可以向左或向右发射,最远距离为 distance[i] 米。子弹会摧毁其射程内路径上的每一堵墙。机器人是固定的障碍物:如果子弹在到达墙壁前击中另一个机器人,它会立即在该机器人处停止,无法继续前进。

返回机器人可以摧毁墙壁的最大数量。

注意:

  • 墙壁和机器人可能在同一位置;该位置的墙壁可以被该位置的机器人摧毁。
  • 机器人不会被子弹摧毁。

示例

示例 1: 输入:robots = [4], distance = [3], walls = [1,10] 输出:1 解释:robots[0] = 4 向左发射,distance[0] = 3,覆盖范围 [1, 4],摧毁了 walls[0] = 1。

示例 2: 输入:robots = [10,2], distance = [5,1], walls = [5,2,7] 输出:3 解释:

  • robots[0] = 10 向左发射,distance[0] = 5,覆盖范围 [5, 10],摧毁了 walls[0] = 5 和 walls[2] = 7。
  • robots[1] = 2 向左发射,distance[1] = 1,覆盖范围 [1, 2],摧毁了 walls[1] = 2。

示例 3: 输入:robots = [1,2], distance = [100,1], walls = [10] 输出:0 解释:在这个例子中,只有 robots[0] 能够到达墙壁,但它向右的射击被 robots[1] 挡住了,因此答案是 0。

错误解法:线段树 + 动态规划

动态规划的状态表示

dp[i] 表示只摧毁位置 ≤ i 的墙,最后能销毁多少堵墙。且之后不会消耗 ≤ i 的墙。 最大值线段树 maxTree 记录最大值。

动态规划的顺序

按机器人的位置从小到大处理。

动态规划的转移方程

每个机器人枚举两种状态,向左射击,向右射击。

错误原因

由于两个机器人的射击范围不能重叠,否则会重复统计。故向左射击不一定是最大射程,各射程要一一枚举。 例如:robots = {4,10}, distance = {3,3}, walls = {6,7,8}。 第二个机器人向左射击能到 {7,8,9,10}。第一个机器人向右射击到 7,第二个机器人向左射击到 8,才是正解。

template<class TSave, class TRecord>
class CRangUpdateLineTree {
protected:
    virtual void OnQuery(TSave& ans, const TSave& save, const int& iSaveLeft, const int& iSaveRight) = 0;
    = ;
    
};

virtual void OnUpdate(TSave& save, const int& iSaveLeft, const int& iSaveRight, const TRecord& update)
0
// ... (省略部分实现细节)
// ... (更多模板类定义)

正确解法

某个向右的机器人和某个向左的机器人射程重叠后。向右的机器人射程不变,向左的机器人缩短射程使之不重叠。向右射击仍然是一种状态,故只讨论向左。 令向左的机器人位于 x2,向左能射击到 x1。 则:射程非最大向左的最大值为 max_{x1}^{x2-1}( dp[x] + f(x) ),其中 f(x) 是处于 x+1 ~ x2 的墙数。 令 g(x) 是 ≤ x 的墙数。 则 射程非最大向左的最大值为 max_{x1}^{x2-1}( dp[x] + g(x2) - g(x) ) = g(x2) + max_{x1}^{x2-1}( dp[x] - g(x) )。 我们用最大值线段树 maxTree2 记录:dp[x] - g(x)。 向左射击的最大值为:max(射程非最大向左的最大值,射程最大向左的最大值)。

内存超限代码
class Solution {
public:
    int maxWalls(vector<int>& robots, vector<int>& distance, vector<int>& walls) {
        const int N = robots.size();
        const int M = (int)(1e9 + 2e5);
        sort(walls.begin(), walls.end());
        // ... (具体实现逻辑)
    }
};

空间超限的解决方法

一、离散化。 二、改用最大值树状数组。

核心代码
template<class T=int>
class CDiscretize {
public:
    CDiscretize(vector<T> nums) {
        sort(nums.begin(), nums.end());
        nums.erase(std::unique(nums.begin(), nums.end()), nums.end());
        m_nums = nums;
        for(int i = 0; i < nums.size(); i++) {
            m_mValueToIndex[nums[i]] = i;
        }
    }
    // ... (其他方法)
};

class Solution {
public:
    int maxWalls(vector<int>& robots, vector<int>& distance, vector<int>& walls) {
        N = robots.size();
        Init(robots, distance, walls);
        CSetMaxLineTree<int,int> maxTree(M+1, 0), maxTree2(M+1, -1000'000);
        for(const auto& [x1, x2, x3] : m_xs) {
            // ... (计算逻辑)
        }
        return maxTree.QueryAll();
    }
    // ... (初始化函数)
};

简单版 DP

性质一:如果机器人和墙挨着一起,此墙一定被摧毁。故只考虑不挨着机器人的墙。 性质二:由于子弹遇到机器人会停止,故墙只会被相邻的机器人摧毁。

动态规划的状态表示

dp0[n] 表示第 0 ~ i 号机器人都已经射击完毕,且最后一个机器人向左(右)射击能摧毁最后的墙数。 空间复杂度:O(n) 为了方便处理边界情况,增加一个机器人标兵,射击距离都是 0,位置分别在正负无穷大。

动态规划的填表顺序

n = 1 to N 枚举后继状态和选择。

动态规划的转移方程

如果 i-1 和 i 都向左射击,两者不会摧毁同一道墙。 如果 i-1 向右和 i 向左射击,两者可能摧毁同一道墙。需要去重。i 向右能够摧毁 g1 道墙,i-1 向左能够摧毁 g0 道墙,i 和 i-1 之间的机器人数量 c,则重复的墙数为:max(0, g1 + g0 - c)。 如果 i 向右射击,i-1 无论向左还是向右,两者都不会摧毁同一道墙。

代码
class Solution {
public:
    int maxWalls(vector<int>& robots, vector<int>& distance, vector<int>& walls) {
        const int N = robots.size();
        const int M = int(1e9 + 1e5 + 1);
        sort(walls.begin(), walls.end());
        vector<pair<int,int>> rd;
        for(int i = 0; i < N; i++) {
            rd.emplace_back(robots[i], distance[i]);
        }
        rd.emplace_back(INT_MIN / 2, 0);
        rd.emplace_back(INT_MAX / 2, 0);
        sort(rd.begin(), rd.end());
        // ... (DP 逻辑)
    }
};

目录

  1. 3661. 可以被机器人摧毁的最大墙壁数目
  2. 示例
  3. 错误解法:线段树 + 动态规划
  4. 动态规划的状态表示
  5. 动态规划的顺序
  6. 动态规划的转移方程
  7. 错误原因
  8. 正确解法
  9. 内存超限代码
  10. 空间超限的解决方法
  11. 核心代码
  12. 简单版 DP
  13. 动态规划的状态表示
  14. 动态规划的填表顺序
  15. 动态规划的转移方程
  16. 代码
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Python 异步数据汇聚与并行计算框架设计与实现
  • Docker 基础使用指南
  • 进阶数据结构:AVL 树
  • 低代码表单设计避坑指南:PHP 工程师需掌握的 5 大核心原则
  • Rye:一款实验性质的 Python 包管理系统
  • Vivado 项目 Git 版本管理实战指南
  • Python 爬虫变现方式解析:外包、产品与量化交易
  • Ollama 本地部署与运行开源大语言模型指南
  • Python 全栈开发:MySQL 与 Redis 数据库集成指南
  • OpenClaw 的 SOUL.md:用自然语言定义 AI 代理身份与行为边界
  • Redis Hash 与 List 实战:数据结构、指令与场景优化
  • 详解 Java 中的 @Schema 注解
  • iOS 26 适配:UITabBar 液态玻璃与 WiFi 权限处理方案
  • MVP 到千万级并发:AI 在前后端开发中的差异化落地指南
  • 注意力机制与 Transformer 模型实战
  • Java 栈与队列数据结构及代码实现
  • 英伟达市值单日蒸发近 6000 亿美元,DeepSeek 开源 Janus-Pro 多模态模型
  • OpenClaw 实操指南:Claude Code 本地部署与飞书集成
  • macOS 本地部署 OpenClaw 智能体框架指南
  • AI 编程助手选型指南:Claude Code、Cursor、Aider 与 Copilot 对比

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online