C++ 模拟题 力扣495. 提莫攻击 题解 每日一题

文章目录


题目描述

题目链接:力扣495. 提莫攻击

题目描述:

示例 1:

输入:timeSeries = [1,4], duration = 2

输出:4

解释:

第 1 秒攻击后,中毒状态持续到第 1+2-1 = 2 秒(共 2 秒);

第 4 秒攻击后,中毒状态持续到第 4+2-1 = 5 秒(共 2 秒);

总中毒时长为 2+2 = 4 秒。
示例 2:

输入:timeSeries = [1,2], duration = 2

输出:3

解释:

第 1 秒攻击后,中毒状态本应持续到第 2 秒;

但第 2 秒提莫再次攻击,中毒状态刷新为持续到第 3 秒;

总中毒时长为 3 秒(从第 1 秒到第 3 秒)。
提示:

1 <= timeSeries.length <= 10^4

0 <= timeSeries[i], duration <= 10^7

timeSeries 按 非递减 顺序排列(题目保证输入有序,无需额外排序)

为什么这道题值得练?

这道题是 "区间重叠问题"的简化版 ,也是笔试中高频出现的"场景理解类模拟题"。它的核心难点不在于算法复杂度,而在于"把游戏场景转化为数学逻辑"------比如理解"后一次攻击会刷新中毒时间,导致前后两次中毒区间可能重叠"。

练这道题能帮你:

  1. 培养"场景转逻辑"的能力:很多算法题都有生活化/游戏化背景,学会剥离场景、提炼核心问题(本题即"计算多个可能重叠的区间总长度")是关键,通过简单题来锻炼我们准确的捕捉题目中的细节,快速精准的模拟。
  2. 强化"边界处理"意识:比如"最后一次攻击的中毒时长无需判断重叠,直接加duration",这类细节容易漏。
  3. 掌握"线性遍历"的高效写法:时间复杂度O(n)、空间复杂度O(1)的解法,减少代码体量。

算法原理

要解决这道题,核心是搞懂"两次攻击的中毒区间是否重叠"------这是决定总时长计算方式的关键。

那么我们可以通过一个数学的规律性的方法来进行下简化,就能很轻松的判断是否重叠的问题。

1.判断中毒区间是否重叠

假设我们第一次中毒时间是 a ,第二次中毒的时间是 b ,中毒持续时间是 d 那么如下图👇:

即相邻两次的中毒间隔(b - a)与 中毒持续时间(duration)进行判断就可以快速的将情况分类。

2. 分情况计算中毒时间

通过第一步的判断,我们就可以轻易来进行分类统计

情况1:不重叠

例:timeSeries = [1,4]duration=2

第1次结束时间=1+2-1=2,第2次开始时间=4 → 2 < 4,无重叠。

此时第 i 次攻击的贡献是完整的 duration 秒。

情况2:重叠

例:timeSeries = [1,3]duration=4

第1次结束时间=4,第2次开始时间=3 → 4 >= 3,有重叠。

因为再次攻击会重置中毒计数时间,所以此时第 i 次攻击的贡献是"从第i次开始到第i+1次开始前"的时间,即 timeSeries[i+1] - timeSeries[i] 秒。

3. 处理最后一次攻击

无论前面的攻击是否重叠,最后一次攻击的中毒时长一定是完整的 duration ------因为没有后续攻击来"打断"它的中毒时间。这是容易被忽略的关键边界,也是代码中需要单独处理的部分。

代码实现时的细节

虽说这奥体的思路很简单,但是有几个在实现代码的时候要注意的细节:
细节1:遍历范围

因为我们要比较"当前攻击"和"下一次攻击",所以遍历只需要到 timeSeries.size()-2(即倒数第二次攻击)。比如数组长度为 n,索引从 0n-1,我们只遍历 0n-2,这样 i+1 不会越界。
细节2:处理特殊情况

duration = 0 时:无论攻击多少次,中毒时长都是 0(代码中 ret + 0 自然成立,无需额外判断)

timeSeries 只有一个元素时:遍历不会进入循环,直接返回 0 + duration(正好是正确结果)。

代码实现

cpp 复制代码
class Solution {
public:
    int findPoisonedDuration(vector<int>& timeSeries, int duration) {
        int ret = 0;
        // 遍历到倒数第二次攻击(i+1不越界)
        for (int i = 0; i < timeSeries.size() - 1; i++) {
            // 比较两次攻击的间隔与duration:取较小值作为当前攻击的贡献
            if (timeSeries[i + 1] - timeSeries[i] >= duration) {
                ret += duration;
            } else {
                ret += timeSeries[i + 1] - timeSeries[i];
            }
        }
        // 最后一次攻击的贡献是完整的duration
        return ret + duration;
    }
};

代码性能分析:

  1. 时间复杂度O(n):仅遍历一次数组(n为攻击次数),效率极高;
  2. 空间复杂度O(1) :只使用了一个变量ret存储结果,无额外空间消耗;
  3. 逻辑清晰:区分"中间攻击"和"最后一次攻击",避免了边界错误;
  4. 鲁棒性强 :自然处理了duration=0timeSeries长度为1等特殊情况。

总结

解决"场景类模拟题",关键在于"先拆解逻辑,再写代码"。以这道题为例,我们可以提炼出三个通用步骤:

  1. 场景转模型 🧩:把"中毒时间"转化为"区间",把"攻击刷新中毒"转化为"区间重叠判断";
  2. 分情况讨论 📊:明确"重叠"和"不重叠"两种情况的计算规则,避免逻辑混乱;
  3. 抓边界特例 🚧:单独处理"最后一次攻击""特殊输入(如duration=0)",防止代码漏洞。

掌握这种"从场景到逻辑、从通用到特例"的思考方式,再遇到类似的模拟题(比如"合并区间""任务调度"),就能快速找到解题思路。

下题预告

下一篇我们来练一道"场景化字符串模拟"的经典题------力扣6. Z字形变换

这道题不像"提莫攻击"那样直接关联"区间",而是需要我们先理解"Z字形排列"的空间场景,再把"排列规则"转化为字符串操作的逻辑------它的难点在于:

  1. 如何把"Z字形"这种可视化的排列方式,拆解成"行与列的移动规律"(比如"向下走到底后向上拐""每一行字符的下标有什么规律");
  2. 如何用简洁的代码模拟排列过程(避免用二维数组浪费空间,或因逻辑混乱导致下标越界);
  3. 如何通过"找规律"优化解法(从"模拟排列"升级到"直接计算每一行字符的位置",进一步提升效率)。

这道题能帮我们进一步强化"场景转逻辑"的能力------尤其是面对"可视化场景"时,如何把抽象的图形规律,转化为可执行的代码逻辑。感兴趣的朋友可以先提前看看题目,试着在纸上画一画"Z字形排列"的过程,比如输入"PAYPALISHIRING"、行数3时的排列情况,提前感受下场景背后的规律~

如果这篇内容对你有帮助,别忘了 点赞👍 + 收藏⭐ + 关注👀 哦!有问题欢迎在评论区留言,我会认真思考并及时回复!

相关推荐
_OP_CHEN8 小时前
C++进阶:(三)深度解析二叉搜索树原理及实现
开发语言·数据结构·c++·二叉树·二叉搜索树·键值对
古译汉书8 小时前
Stm32江科大入门教程--各章节详细笔记---查阅传送门
数据结构·stm32·单片机·嵌入式硬件·算法
郝学胜-神的一滴10 小时前
深入解析C++命令模式:设计原理与实际应用
开发语言·c++·程序人生·软件工程·命令模式
ShineSpark10 小时前
Crashpad介绍
c++·windows
Jasmine_llq10 小时前
《P2656 采蘑菇》
算法·强连通分量·广度优先搜索(bfs)·tarjan 算法·图的缩点操作·有向无环图(dag)·最长路径
芥子沫10 小时前
《人工智能基础》[算法篇3]:决策树
人工智能·算法·决策树
mit6.82410 小时前
dfs|位运算
算法
苏纪云10 小时前
算法<C++>——双指针 | 滑动窗口
数据结构·c++·算法·双指针·滑动窗口
保持低旋律节奏10 小时前
算法——二叉树、dfs、bfs、适配器、队列练习
算法·深度优先·宽度优先