const solve = (nums) => { let left = 0, right = nums.length - 1; while (left < right) { const sum = nums[left] + nums[right]; if (sum === target) return [left, right]; }}
Problem Walkthrough

Task Scheduler LeetCode 621 Guide

LeetCode 621 looks like a simulation problem, but the optimal solution is a single formula. Learn the greedy math insight that turns CPU task scheduling with cooldowns into one line of code.

9 min read|

Task Scheduler (#621): greedy math, not simulation

The formula that turns a scheduling problem into one line of math

Task Scheduler LeetCode: A Scheduling Problem With a Math Solution

Task Scheduler (#621) is one of those LeetCode problems that tricks you into thinking you need a complex simulation. You have a list of CPU tasks, a cooldown period n between identical tasks, and you need to find the minimum number of intervals to execute them all. Your first instinct might be to build a priority queue and simulate round by round — but the elegant solution is pure greedy math.

This problem appears frequently at Amazon, DoorDash, Uber, and Bloomberg, making it one of the most-asked scheduling and greedy problems in real coding interviews. It tests whether you can see past the simulation trap and recognize that the most frequent task dictates the entire schedule structure.

In this walkthrough, we will break down exactly why the task scheduler leetcode problem has a formula-based O(n) solution, how to derive it from scratch, and what edge cases you need to handle. By the end, you will understand the one-line formula that replaces hundreds of lines of simulation code.

Understanding the Problem

You are given an array of tasks represented by characters (like ["A","A","A","B","B","B"]) and a non-negative integer n representing the cooldown interval. Between two executions of the same task, there must be at least n intervals. During those intervals you can execute a different task or let the CPU sit idle. The goal is to return the minimum number of intervals the CPU needs to complete all tasks.

The key insight that most people miss on their first attempt is that tasks can be executed in any order. You are not locked into the sequence given in the input array. This freedom to reorder is what makes the greedy approach possible — you can arrange tasks strategically to minimize idle time.

Consider the example tasks = ["A","A","A","B","B","B"] with n = 2. One optimal schedule is A -> B -> idle -> A -> B -> idle -> A -> B, which takes 8 intervals. Notice how we interleave the two most frequent tasks and only idle when we run out of different tasks to fill the gaps.

ℹ️

Interview Frequency

Task Scheduler (#621) appears at Amazon, DoorDash, Uber, and Bloomberg — it's the most-asked scheduling/greedy problem and tests whether you can avoid the simulation trap.

The Greedy Insight: Most Frequent Task Determines the Structure

The task scheduler greedy approach starts with a critical observation: the most frequent task is the bottleneck. If task A appears 3 times and the cooldown is n = 2, then A alone forces at least (3-1) * (2+1) + 1 = 7 intervals no matter what. Each "frame" between consecutive A executions must be at least n+1 slots wide.

Think of it as building a grid. The most frequent task creates rows, and each row has n+1 columns. You place the most frequent task at the start of each row, then fill the remaining slots with other tasks. If you have enough different tasks, every slot gets filled and there is zero idle time. If you do not have enough, the empty slots become idle intervals.

This frame-based thinking is the core of the task scheduler explained simply. You are not simulating anything — you are calculating how many frames you need, how wide each frame is, and whether you have enough tasks to fill all the slots. That calculation collapses into a single formula.

  • The most frequent task creates (maxFreq - 1) full frames of width (n + 1)
  • A final partial frame holds one slot for each task that has the maximum frequency
  • Other tasks fill the empty slots in the frames, reducing idle time
  • If total tasks exceed the frame capacity, no idle time is needed at all

The Task Scheduler Formula

The entire task scheduler leetcode solution boils down to one formula: intervals = max(len(tasks), (maxFreq - 1) * (n + 1) + countOfMaxFreq). That is it. One line of math that handles every possible input configuration.

Here is what each piece means. maxFreq is the highest frequency among all tasks — count how many times the most common task appears. countOfMaxFreq is how many distinct tasks share that maximum frequency. For example, if A appears 3 times and B appears 3 times, then maxFreq = 3 and countOfMaxFreq = 2.

The expression (maxFreq - 1) * (n + 1) calculates the total slots in all full frames. You have (maxFreq - 1) gaps between consecutive executions of the most frequent task, and each gap must span (n + 1) intervals (the cooldown n, plus one slot for the task itself). Then you add countOfMaxFreq for the final partial frame — one slot for each task that appears maxFreq times.

The max() with len(tasks) handles the case where you have so many different tasks that the frame structure has no idle time. When tasks overflow the frames, the answer is simply the total number of tasks because every slot is filled and the cooldown constraint is automatically satisfied.

💡

The Key Formula

The formula is: max(len(tasks), (maxFreq-1)*(n+1) + countOfMaxFreq). The max() handles two cases: enough tasks to fill all gaps (no idle) or not enough (idle needed). One formula, all cases.

Why the Formula Works: A Visual Walkthrough

Let us trace through an example to see the cpu task scheduling formula in action. Suppose tasks = ["A","A","A","A","B","B","B","C","C","D"] and n = 2. First, count frequencies: A appears 4 times, B appears 3 times, C appears 2 times, D appears once. So maxFreq = 4 and countOfMaxFreq = 1 (only A has frequency 4).

The formula gives us (4 - 1) * (2 + 1) + 1 = 9 + 1 = 10. We also have len(tasks) = 10. So intervals = max(10, 10) = 10. The schedule looks like: A B C | A B C | A B D | A. Three full frames of 3 slots each, plus the final A. Every slot is filled, zero idle time.

Now consider tasks = ["A","A","A","B","B"] with n = 3. Frequencies: A = 3, B = 2. maxFreq = 3, countOfMaxFreq = 1. Formula: (3 - 1) * (3 + 1) + 1 = 8 + 1 = 9. len(tasks) = 5. So intervals = max(5, 9) = 9. The schedule: A B idle idle | A B idle idle | A. There are not enough tasks to fill the 4-wide frames, so idle slots appear.

The max() function elegantly toggles between these two regimes. When tasks are plentiful, len(tasks) dominates — no idle needed. When tasks are scarce relative to the cooldown, the frame calculation dominates — idle slots are unavoidable. The task scheduler cooldown behavior is fully captured by this single comparison.

Edge Cases and Variations

The formula handles every edge case without special-casing. When n = 0 (no cooldown), the formula gives (maxFreq - 1) * 1 + countOfMaxFreq, but len(tasks) will always be greater or equal, so the answer is simply the total number of tasks. Tasks can run back to back with no restriction.

When all tasks are the same (e.g., ["A","A","A","A"] with n = 2), maxFreq = 4, countOfMaxFreq = 1, and the formula gives (3) * (3) + 1 = 10. The schedule is A idle idle A idle idle A idle idle A — exactly what you would expect with forced cooldowns between every execution.

When all tasks are different (e.g., ["A","B","C","D","E"]), every task appears once. maxFreq = 1, so (1 - 1) * (n + 1) + countOfMaxFreq = 0 + 5 = 5. And len(tasks) = 5. No idle needed because every task is unique. The cooldown constraint never triggers.

Multiple tasks with the same max frequency are also clean. If A, B, and C each appear 3 times and n = 2, then maxFreq = 3 and countOfMaxFreq = 3. Formula: (2) * (3) + 3 = 9. The final frame is 3 slots wide (one for each max-frequency task), and the schedule works out perfectly: A B C | A B C | A B C.

  • n = 0: answer is always len(tasks) — no cooldown means no idle
  • All same task: formula reduces to (count - 1) * (n + 1) + 1
  • All different tasks: answer is len(tasks) since no repeats exist
  • Multiple max-frequency tasks: countOfMaxFreq grows the final frame
⚠️

Avoid the Simulation Trap

Don't simulate the schedule — building a priority queue and simulating round by round works but is O(n log 26) and harder to code. The formula is O(n) and fits in 5 lines.

What Task Scheduler Teaches You

The task scheduler leetcode problem is a masterclass in recognizing when greedy math beats simulation. The priority-queue simulation approach works — you can build a max heap, pop the top k tasks each round, and re-insert them after decrementing — but it runs in O(n log 26) time and requires significantly more code. The formula runs in O(n) with a single pass to count frequencies.

This same pattern of frequency analysis determining structure appears in other problems. Reorganize String (#767) asks you to rearrange characters so no two adjacent characters are the same — the approach is nearly identical. Rearrange String k Distance Apart (#358) generalizes the cooldown concept. Once you internalize the frame-based greedy thinking from Task Scheduler, these problems become straightforward.

The deeper lesson is that many scheduling and arrangement problems that look like they need simulation or dynamic programming actually have closed-form solutions hiding behind frequency analysis. When you see a problem about ordering items with constraints between identical items, count frequencies first. The most frequent item will almost always determine the answer structure.

Practice the task scheduler formula until you can derive it from scratch in under two minutes. Use YeetCode flashcards to drill the pattern — recognizing that "most frequent element determines the frame" is the key insight that transfers across an entire family of greedy problems.

Ready to master algorithm patterns?

YeetCode flashcards help you build pattern recognition through active recall and spaced repetition.

Start practicing now