You have a list of tasks labeled A–Z and a cooldown n: the same task cannot run twice within n intervals. The machine must schedule the tasks to finish in the fewest total intervals, using idle slots when nothing is eligible.
The key insight: the machine never waits if it can help it. At each interval it picks the most frequent eligible task — a greedy choice that a max-heap makes natural. But cooldown matters: a task that just ran must sit out for n ticks, so the machine keeps a queue of "cooling" tasks with their next-available time, and only re-enters the heap when that time arrives.
Approach in steps:
- Count task frequencies; push all into a max-heap.
- Loop over time: pop the hottest eligible task, decrement its count, push it into the cooldown queue with
available_at = time + n + 1if it still has runs left. - When the queue's head becomes available, push it back into the heap. Count every interval, idle or not.
import heapq
from collections import Counter, deque
def leastInterval(tasks, n):
heap = [-c for c in Counter(tasks).values()]
heapq.heapify(heap)
cooling = deque()
time = 0
while heap or cooling:
if heap:
c = -heapq.heappop(heap)
c -= 1
if c:
cooling.append((c, time + n + 1))
time += 1
if cooling and cooling[0][1] == time:
heapq.heappush(heap, -cooling.popleft()[0])
return timeTime is O(m log k) for m intervals and k distinct tasks; space O(k).
Trickiest edge case: n = 0 — no cooldown, so the answer is just len(tasks) and the cooldown queue must not gate anything. Second: ties among tasks with equal counts — the greedy pick among them is arbitrary and still optimal, because only relative frequencies set the bound.