Task Scheduler — Queue + Heap Approach
Solve the Task Scheduler problem (LeetCode 621) using a queue and max-heap. Covers the greedy formula and simulation approaches with Python code.
What you'll learn
- ✓Two approaches: greedy formula and heap+queue simulation
- ✓Why the most frequent task determines minimum intervals
- ✓How a cooldown queue tracks when tasks become available
- ✓Complexity analysis for both approaches
Prerequisites
- •Queue basics — see Stacks & Queues Intro
- •Heap basics — see Heap Intro
Given tasks with a cooldown period n (same task must have at least n intervals between executions), find the minimum number of intervals needed to execute all tasks.
Greedy Formula Approach
The task with the highest frequency determines the structure:
from collections import Counter
def least_interval_formula(tasks, n):
"""
Greedy formula approach.
Time: O(t), Space: O(1) — at most 26 task types
"""
freq = Counter(tasks)
max_freq = max(freq.values())
max_count = sum(1 for v in freq.values() if v == max_freq)
# (max_freq - 1) groups of (n + 1) slots, plus final group
result = (max_freq - 1) * (n + 1) + max_count
return max(result, len(tasks))
Why This Works
Tasks: A=6, B=1, C=1, D=1, E=1, F=1, n=2
A _ _ | A _ _ | A _ _ | A _ _ | A _ _ | A
A B C | A D E | A F _ | A _ _ | A _ _ | A
(max_freq-1) = 5 groups of (n+1) = 3 slots = 15
Plus max_count = 1 (only A has max freq)
Total = 16
But we have 11 tasks, and 16 > 11, so answer is 16.
Simulation with Heap + Queue
This approach builds the actual schedule:
import heapq
from collections import Counter, deque
def least_interval(tasks, n):
"""
Simulate scheduling with max-heap and cooldown queue.
Time: O(t × n), Space: O(t)
"""
freq = Counter(tasks)
max_heap = [-cnt for cnt in freq.values()]
heapq.heapify(max_heap)
cooldown = deque() # (available_time, remaining_count)
time = 0
while max_heap or cooldown:
time += 1
if max_heap:
cnt = heapq.heappop(max_heap) + 1 # +1 because negative
if cnt != 0:
cooldown.append((time + n, cnt))
if cooldown and cooldown[0][0] == time:
_, cnt = cooldown.popleft()
heapq.heappush(max_heap, cnt)
return time
Trace (Simulation)
Tasks: ['A','A','A','B','B','B'], n=2
time=1: heap=[-3A,-3B] → run A(-2), cooldown=[(3,-2A)]
time=2: heap=[-3B] → run B(-2), cooldown=[(3,-2A),(4,-2B)]
time=3: heap=[] → idle, cooldown releases A → heap=[-2A], cooldown=[(4,-2B)]
time=4: heap=[-2A] → run A(-1), cooldown releases B → heap=[-2B], cool=[(6,-1A)]
time=5: heap=[-2B] → run B(-1), cooldown=[(6,-1A),(7,-1B)]
time=6: releases A → run A(0), cooldown=[(7,-1B)]
time=7: releases B → run B(0)
time=8: done
Schedule: A B _ A B _ A B → 8 intervals
Edge Cases
- n = 0 — no cooldown, answer is len(tasks)
- All unique tasks — no cooldown needed if enough variety
- Single task type — answer is
(freq - 1) * (n + 1) + 1 - Multiple tasks tied for max frequency —
max_counthandles this
When to Use Each Approach
| Approach | When |
|---|---|
| Formula | Only need the count, not the schedule |
| Simulation | Need the actual execution order |
Related Problems
- Reorganize String (LeetCode 767) — no adjacent same characters
- Rearrange String k Distance Apart (LeetCode 358)
- Task Scheduler II (LeetCode 2365)
Related articles
- DSA Deque Design Patterns — Sliding Window, Palindrome, Work Stealing
Master deque design patterns including sliding window maximum, palindrome checking, work stealing, and BFS/DFS hybrid. Python implementations.
- DSA Design Front Middle Back Queue — Two Deques (LeetCode 1670)
Design Front Middle Back Queue using two balanced deques. Python solution with O(1) operations, step-by-step trace, and complexity analysis for LeetCode 1670.
- DSA Open the Lock — BFS on State Space (LeetCode 752)
Open the Lock problem solved with BFS on 4-digit state space. Python solution with deadend handling, bidirectional BFS optimization, and complexity analysis.
- DSA Sliding Window Maximum Using Deque
Solve the sliding window maximum problem in O(n) using a monotonic deque. Covers the algorithm, Python code, visual traces, and variations.