Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
You are given an array of CPU tasks, each labeled with a letter from A to Z, and a number n. Each CPU interval can be idle or allow the completion of one task. Tasks can be completed in any order, but there's a constraint: there has to be a gap of at least n intervals between two tasks with the same label.
Return the minimum number of CPU intervals required to complete all tasks.
Example 1:
Input: tasks = ["A","A","A","B","B","B"], n = 2
Output: 8
Explanation: A possible sequence is: A -> B -> idle -> A -> B -> idle -> A -> B.
After completing task A, you must wait two intervals before doing A again. The same applies to task B. In the 3rd interval, neither A nor B can be done, so you idle. By the 4th interval, you can do A again as 2 intervals have passed.
Example 2:
Input: tasks = ["A","C","A","B","D","B"], n = 1
Output: 6
Explanation: A possible sequence is: A -> B -> C -> D -> A -> B.
With a cooling interval of 1, you can repeat a task after just one other task.
Example 3:
Input: tasks = ["A","A","A", "B","B","B"], n = 3
Output: 10
Explanation: A possible sequence is: A -> B -> idle -> idle -> A -> B -> idle -> idle -> A -> B.
There are only two types of tasks, A and B, which need to be separated by 3 intervals. This leads to idling twice between repetitions of these tasks.
Constraints:
1 <= tasks.length <= 104tasks[i] is an uppercase English letter.0 <= n <= 100Problem summary: You are given an array of CPU tasks, each labeled with a letter from A to Z, and a number n. Each CPU interval can be idle or allow the completion of one task. Tasks can be completed in any order, but there's a constraint: there has to be a gap of at least n intervals between two tasks with the same label. Return the minimum number of CPU intervals required to complete all tasks.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map · Greedy
["A","A","A","B","B","B"] 2
["A","C","A","B","D","B"] 1
["A","A","A", "B","B","B"] 3
rearrange-string-k-distance-apart)reorganize-string)maximum-number-of-weeks-for-which-you-can-work)find-minimum-time-to-finish-all-jobs-ii)task-scheduler-ii)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #621: Task Scheduler
class Solution {
public int leastInterval(char[] tasks, int n) {
int[] cnt = new int[26];
int x = 0;
for (char c : tasks) {
c -= 'A';
++cnt[c];
x = Math.max(x, cnt[c]);
}
int s = 0;
for (int v : cnt) {
if (v == x) {
++s;
}
}
return Math.max(tasks.length, (x - 1) * (n + 1) + s);
}
}
// Accepted solution for LeetCode #621: Task Scheduler
func leastInterval(tasks []byte, n int) int {
cnt := make([]int, 26)
x := 0
for _, c := range tasks {
c -= 'A'
cnt[c]++
x = max(x, cnt[c])
}
s := 0
for _, v := range cnt {
if v == x {
s++
}
}
return max(len(tasks), (x-1)*(n+1)+s)
}
# Accepted solution for LeetCode #621: Task Scheduler
class Solution:
def leastInterval(self, tasks: List[str], n: int) -> int:
cnt = Counter(tasks)
x = max(cnt.values())
s = sum(v == x for v in cnt.values())
return max(len(tasks), (x - 1) * (n + 1) + s)
// Accepted solution for LeetCode #621: Task Scheduler
use std::collections::{BinaryHeap, VecDeque, HashMap};
impl Solution {
pub fn least_interval(tasks: Vec<char>, n: i32) -> i32 {
let mut count = HashMap::new();
let mut max_heap = BinaryHeap::new();
for task in tasks {
let count = count.entry(task).or_insert(0);
*count += 1;
}
for (key, val) in count.iter() {
max_heap.push(*val);
}
let mut time = 0;
let mut deque: VecDeque<(i32,i32)> = VecDeque::new();
while deque.len() > 0 || max_heap.len() > 0 {
time += 1;
if max_heap.len() == 0 {
time = deque[0].1;
}
else {
let cnt = max_heap.pop().unwrap() - 1;
if cnt != 0 {
deque.push_back((cnt, time + n));
}
}
if deque.len() > 0 && deque[0].1 == time {
max_heap.push(deque.pop_front().unwrap().0);
}
}
time
}
}
// Accepted solution for LeetCode #621: Task Scheduler
function leastInterval(tasks: string[], n: number): number {
const charMap = new Map();
let maxCharCount = 0;
let maxChar = tasks[0];
for (let char of tasks) {
charMap.set(char, (charMap.get(char) || 0) + 1);
if (charMap.get(char) > maxCharCount) {
maxCharCount = charMap.get(char);
maxChar = char;
}
}
let idleCount = (maxCharCount - 1) * n;
charMap.forEach((count, char) => {
// 'return' inside forEach() serve as 'continue'
if (char === maxChar) {
return;
}
if (count === maxCharCount) {
idleCount -= count - 1;
} else {
idleCount -= count;
}
});
if (idleCount <= 0) {
return tasks.length;
}
return tasks.length + idleCount;
}
Use this to step through a reusable interview workflow for this problem.
Try every possible combination of choices. With n items each having two states (include/exclude), the search space is 2ⁿ. Evaluating each combination takes O(n), giving O(n × 2ⁿ). The recursion stack or subset storage uses O(n) space.
Greedy algorithms typically sort the input (O(n log n)) then make a single pass (O(n)). The sort dominates. If the input is already sorted or the greedy choice can be computed without sorting, time drops to O(n). Proving greedy correctness (exchange argument) is harder than the implementation.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.
Wrong move: Locally optimal choices may fail globally.
Usually fails on: Counterexamples appear on crafted input orderings.
Fix: Verify with exchange argument or monotonic objective before committing.