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

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

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

RedisGeek发布于 2026/4/6更新于 2026/10/19101 浏览
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. 代码

更多推荐文章

查看全部
  • 滑动窗口算法专题:四道经典题目深度解析
  • Dify + Skill 本地部署大模型智能体:企业级 AI Agent 构建指南
  • Stable Diffusion 模型加载报错修复指南
  • AI 时代,为何架构师反而更稀缺了?
  • Deepseek 与 Kimi 联动:构建智能 PPT 创作工作流
  • Python 网络爬虫基础教程:豆瓣电影 Top250 数据抓取实战
  • Linux 下 FFmpeg C++ 音视频解码与推流实战
  • AI 大模型应用场景落地策略:从理论到实践
  • C++ 模板进阶:非类型参数与特化机制
  • TapNow 影视级 AI 视频平台实测:更可控的镜头和更稳的一致性
  • 基于 RetinaFace 与 CurricularFace 的身份核验系统实现
  • Python 微信小程序班级学生奖惩成绩信息管理系统
  • GitHub Desktop 界面中文本地化完整教程
  • Linux 基础:冯诺依曼架构与进程管理
  • 8 款 AI 论文降重工具对比:智能改写与写作功能分析
  • Git 与 TortoiseGit 本地环境搭建实战指南
  • 10款主流AI降重工具功能对比与使用指南
  • Python 操作 Word 文档入门与实战指南
  • MiniOneRec 论文解读:生成式推荐框架
  • Python 语言概述、应用现状及学习路径指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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