In the "Teemo Attacking" problem, you are given an integer array timeSeries
representing the times at which Teemo attacks an enemy, and an integer duration
representing how long each attack's poison effect lasts. When Teemo attacks at time t
, the enemy is poisoned from time t
up to but not including time t + duration
.
If another attack happens before the previous poison effect ends, the poison timer resets, but overlapping poison durations should not be double-counted.
Your task is to calculate the total time the enemy is poisoned.
timeSeries
(List of integers), duration
(integer)timeSeries.length
≤ 104timeSeries[i]
, duration
≤ 107timeSeries
is sorted in non-decreasing orderTo solve this problem, let's first consider the brute-force approach: for each attack, we could mark every second the enemy is poisoned, but this quickly becomes inefficient for large inputs.
The key insight is that poison durations can overlap. If two attacks are spaced apart by less than duration
, the second attack's poison effect starts before the first one ends, so their poison durations overlap. Instead of counting the full duration
for both, we should only count the non-overlapping part.
Therefore, for each attack (except the last), the actual poison time contributed is the minimum of duration
and the gap to the next attack. The last attack always contributes duration
since nothing comes after it.
total
, to keep track of the total poisoned time.
timeSeries
array. For each attack except the last:
gap = timeSeries[i+1] - timeSeries[i]
min(duration, gap)
total
duration
for the last attack (since it always contributes its full duration).
total
as the result.
This approach is efficient, requiring only a single pass through the input array.
Let's use timeSeries = [1, 4]
and duration = 2
as an example.
duration
, so there's no overlap.
Now, consider timeSeries = [1, 2]
and duration = 2
:
The "Teemo Attacking" problem is a great example of how careful analysis of overlapping intervals can lead to an efficient solution. By considering only the non-overlapping portions of each attack's poison effect and always adding the full duration for the last attack, we achieve a one-pass, O(N) solution. This approach avoids unnecessary work and elegantly handles all cases, including overlapping and non-overlapping attacks.
class Solution:
def findPoisonedDuration(self, timeSeries, duration):
if not timeSeries:
return 0
total = 0
for i in range(len(timeSeries) - 1):
gap = timeSeries[i+1] - timeSeries[i]
total += min(duration, gap)
total += duration
return total
class Solution {
public:
int findPoisonedDuration(vector<int>& timeSeries, int duration) {
if (timeSeries.empty()) return 0;
int total = 0;
for (int i = 0; i < timeSeries.size() - 1; ++i) {
int gap = timeSeries[i+1] - timeSeries[i];
total += min(duration, gap);
}
total += duration;
return total;
}
};
class Solution {
public int findPoisonedDuration(int[] timeSeries, int duration) {
if (timeSeries.length == 0) return 0;
int total = 0;
for (int i = 0; i < timeSeries.length - 1; i++) {
int gap = timeSeries[i+1] - timeSeries[i];
total += Math.min(duration, gap);
}
total += duration;
return total;
}
}
var findPoisonedDuration = function(timeSeries, duration) {
if (timeSeries.length === 0) return 0;
let total = 0;
for (let i = 0; i < timeSeries.length - 1; i++) {
let gap = timeSeries[i+1] - timeSeries[i];
total += Math.min(duration, gap);
}
total += duration;
return total;
};