← 返回题目列表

提莫攻击的中毒总时长如何合并重叠时间区间?

简单 第 16 / 24 题 更新于 2026/08/01
区间问题区间合并时间线重叠计算

简化版

提莫攻击每次攻击产生一个中毒区间 [time, time+duration)。相邻攻击如果间隔小于 duration,中毒时间会重叠,新增时长只等于两次攻击间隔;否则新增完整 duration。累加每次新增贡献即可。

详细版

因为 timeSeries 已按升序排列,所以不需要真正构造所有区间。对于相邻两次攻击 time[i-1]time[i],前一次中毒最多持续到 time[i-1]+duration。如果下一次攻击提前发生,重叠部分不能重复计算。

因此每次新增贡献是 min(duration, time[i]-time[i-1]),最后再加上最后一次攻击的完整 duration。时间复杂度 O(n),空间复杂度 O(1)

完整版教学

一、每次攻击对应什么区间

攻击时间为 t,中毒持续 duration,通常表示半开区间:

[t, t + duration)

比如 t=1,duration=2,覆盖时间 [1,3),长度为 2。半开区间可以避免端点重复计算。

二、为什么重叠不能重复算

如果攻击发生在前一次中毒还没结束时,新中毒会刷新或延续效果,但重叠时间只能算一次。

攻击 1: [1,5)
攻击 3: [3,7)
合并后:[1,7),总长 6,不是 8
间隔新增中毒时长
gap >= duration完整 duration
gap < duration只新增 gap

记忆钩子:相邻攻击贡献的是“前一次攻击到这次攻击之间真正新增的时间”。

三、为什么只看相邻攻击

timeSeries 已升序。当前攻击只可能和前一次中毒尾巴发生重叠;更早的攻击如果能影响当前,也一定已经通过前一次覆盖状态体现出来。

t0 <= t1 <= t2
计算 t2 时,只要看 t1 到 t2 的间隔

这让问题从区间合并简化成相邻差值累加。

四、公式怎么来

对第 i 次攻击之前的新增贡献:

gap = timeSeries[i] - timeSeries[i-1]
新增 = min(duration, gap)

最后一次攻击之后没有下一次攻击截断,所以要额外加完整 duration

ans = sum(min(duration, gap_i)) + duration

如果只有一次攻击,答案就是 duration

五、代码模板

int findPoisonedDuration(int[] timeSeries, int duration) {
    if (timeSeries.length == 0) return 0;
    int ans = 0;
    for (int i = 1; i < timeSeries.length; i++) {
        ans += Math.min(duration, timeSeries[i] - timeSeries[i - 1]);
    }
    return ans + duration;
}

这份写法不需要显式维护区间右端,因为相邻差值已经隐含了重叠长度。

六、用数字例子推演

timeSeries=[1,4], duration=2

gap=3 >=2
答案 = 2 + 2 = 4

timeSeries=[1,2], duration=2

第一次 [1,3)
第二次 [2,4)
gap=1
答案 = 1 + 2 = 3

第二个例子里 [2,3) 是重叠段,不能重复计算。

七、常见误区与追问

  • 误区:每次攻击都直接加 duration。 重叠中毒时间会被重复计算。
  • 误区:把端点当闭区间多算 1。 持续时间题更适合半开区间 [t,t+d)
  • 误区:忘记加最后一次 duration。 相邻差值只统计到每次攻击发生前的新增时间。
  • 追问:为什么只看相邻攻击? 时间有序,重叠关系已经被相邻间隔完全决定。
  • 追问:如果 timeSeries 不是有序怎么办? 需要先排序,否则相邻差值无意义。
  • 追问:复杂度是多少? 单次扫描 O(n),额外空间 O(1)

八、加强记忆

提莫攻击就是最轻量的区间合并。每次攻击产生 [t,t+d),相邻攻击间隔小于 d 就重叠,新增只算间隔;间隔大于等于 d 就完整新增。循环里累加 min(duration,gap),最后补上最后一次完整持续时间。