LeetCode #621 Medium

Task Scheduler

Task Scheduler is LeetCode 621 (Medium). A CPU has to run a list of tasks, each an uppercase letter A to Z, with a cooldown n between equal tasks.

  • In each interval the CPU runs exactly one task or stays idle.
  • Two runs of the same letter must be separated by at least n intervals.
  • Tasks may run in any order; different letters have no cooldown between them.

Return the minimum number of intervals needed to finish every task. There are up to 10⁴ tasks and n is at most 100, so the answer should come from the counts, not from simulating every order.

Constraints
  • 1 <= tasks.length <= 10⁴
  • tasks[i] is an uppercase English letter.
  • 0 <= n <= 100
heapgreedycountingmath
Open on LeetCode ↗
02

Intuition

The order of the input does not matter, only how many times each task appears, and one task forces the shape of every schedule: the most frequent one. Its copies must sit n slots apart, so they mark out a frame of cooldown windows that no schedule can be shorter than.

Every other task has at most as many copies as that top task, so it can be spread one per window into the gaps without breaking its own cooldown. Gaps nobody fills become idle. If there are more tasks than gaps, the windows simply grow and no idle is needed. So the answer is the frame size or the task count, whichever is larger.

How to spot this pattern

Scheduling with a minimum gap between equal items, where the order is yours to choose, is decided by the most frequent item. Reorganize String (767) is the LeetCode Task Scheduler picture with n = 1; Rearrange String k Distance Apart (358) needs the actual order, so it uses a max-heap and a cooldown queue.

03

Approach

Try it first

Before reading on, draw a schedule for AAABBB with n = 2 using as few slots as you can. Count the idles, then try to explain the count from the frequencies alone.

1

Count the tasks

Build a frequency count. Let maxFreq be the highest count and numTop the number of tasks that have it. In the task scheduler Python code, Counter(tasks) builds the counts in one pass.

2

Size the frame

  • maxFreq − 1 full rows of n + 1 slots: each row is one cooldown window, starting with a copy of a top task.
  • One last row holding only the numTop top tasks.
  • Total: frames = (maxFreq − 1) × (n + 1) + numTop.
3

Fill the frame with the other tasks

Place the remaining tasks column by column through the first maxFreq − 1 rows. A task with k ≤ maxFreq − 1 copies lands in k different rows, so its copies are always a full window apart. Empty slots that remain are the idle intervals.

4

Handle overflow

If the tasks do not fit in n + 1 columns, keep extending the rows. Gaps only grow, so the cooldown still holds and no idle is needed: the answer is len(tasks). Return max(len(tasks), frames).

04

Task Scheduler solution in Python | C++ | Java

▶1class Solution:
▶2 def leastInterval(self, tasks: List[str], n: int) -> int:
▶3 counts = Counter(tasks).values()
▶4 max_freq = max(counts)
▶5 num_top = sum(1 for c in counts if c == max_freq)
▶6 frames = (max_freq - 1) * (n + 1) + num_top
▶7 return max(len(tasks), frames)
countsA × 3B × 33 slotsrow1row2row3
tasks6
n2cooldown between equal tasks
maxFreq3
Count each task. Order does not matter, only how many of each. The most frequent task, A (3 times), decides the shape: its copies must be at least n + 1 = 3 slots apart, so lay out 3 rows of 3 slots and put one A at the start of each row.
countsA × 3B × 33 slotsrow1Arow2Arow3A
taskA × 3ties the max frequency
max-frequency tasks2they also fill the last row
A appears 3 times, the maximum, so it needs a slot in every row, including the last one. It opens each row.
countsA × 3B × 33 slotsrow1ABrow2ABrow3AB
taskB × 3ties the max frequency
max-frequency tasks2they also fill the last row
B appears 3 times, the maximum, so it needs a slot in every row, including the last one. It takes the next column, right after A. Every max-frequency task adds one slot to the last row, which is why the formula ends in + numTop.
countsA × 3B × 33 slotsrow1ABidlerow2ABidlerow3ABidle2idle slots
idle2cooldown the other tasks cannot cover
row width3
Any slot left empty in the first 2 rows is a cooldown the other tasks could not cover, so the CPU sits idle there. The last row only needs its 2 max-frequency tasks; nothing has to wait after them.
countsA × 3B × 33 slotsrow1ABidlerow2ABidlerow3ABframe2rows×3slots+2last row=8framemax6tasksvs8frame
frames8(f−1)(n+1) + numTop
len(tasks)6never fewer slots than tasks
answer8
Count the slots without building anything. 2 full rows of 3, plus a last row of 2: 8. That is at least the 6 tasks, so the idles are unavoidable and the answer is 8.
countsA × 3B × 33 slotsrow1ABidlerow2ABidlerow3ABtimeA1B23A4B56A7B8
scheduleA B · A B · A B· = idle
answer8
The frames are a real schedule. Reading the rows in order gives A → B → idle → A → B → idle → A → B. Every repeat of a task is at least 2 slots after the previous one, and the length is 8, matching the formula.
05

Common pitfalls

Returning the frame count without the max

✗ Wrong
return (max_freq - 1) * (n + 1) + num_top
✓ Right
return max(len(tasks), (max_freq - 1) * (n + 1) + num_top)

With many distinct tasks the frame is too small. ["A","A","B","B","C","D"] with n = 1 gives a frame of 4, but 6 tasks need at least 6 intervals.

Adding 1 instead of numTop

✗ Wrong
frames = (max_freq - 1) * (n + 1) + 1
✓ Right
frames = (max_freq - 1) * (n + 1) + num_top

Every task tied for the highest count has a copy in the last row. AAABBB, n = 2 ends … A B, so the last row has 2 tasks and the answer is 8, not 7.

Using n instead of n + 1 as the row width

✗ Wrong
frames = (max_freq - 1) * n + num_top
✓ Right
frames = (max_freq - 1) * (n + 1) + num_top

A window holds the task itself plus n cooldown slots. With n as the width, two As end up only n − 1 apart.

06

Edge cases

n = 0

No cooldown: the frame is maxFreq − 1 + numTop, never more than len(tasks), so the answer is len(tasks).

07

Complexity

Time
O(N)
Space
O(1)
N is len(tasks), read once to count. The count table has 26 entries at most, so extra space is constant.
08

Greedy formula vs max-heap simulation

Both are accepted task scheduler solutions. The heap version is the one to reach for when the actual order is required, not just its length.

Frame formula (this page)Max-heap + cooldown queue
TimeO(N)O(N · log 26) plus one step per idle
SpaceO(1)O(26)
Gives the schedule itselfonly by drawing the frameyes, interval by interval
Ideathe most frequent task fixes the lengthalways run the most frequent available task
Generalises toany "min gap between equal items" countRearrange String k Distance Apart (358)
09

Task Scheduler FAQ

Is Task Scheduler the same as the job scheduler LeetCode problems?

No. Searches for a job scheduler on LeetCode usually mean one of two other problems. Maximum Profit in Job Scheduling (1235) picks non-overlapping jobs for the most profit, using sorting, DP and binary search. Minimum Difficulty of a Job Schedule (1335) splits jobs across days with DP. The task scheduler LeetCode problem, 621, has no profits or deadlines: only a cooldown, and the answer depends on the task counts alone.