🧠
Brute Force (Simulation with Idle Insertion)
💡 This approach tries to simulate the scheduling by repeatedly picking the next available task and inserting idle times when necessary. It is intuitive but inefficient for large inputs.
Intuition
At each time unit, pick a task that can be executed (not in cooldown). If none is available, insert idle time. Repeat until all tasks are done.
Algorithm
- Count the frequency of each task.
- Maintain a cooldown queue to track tasks in cooldown.
- At each time unit, pick the highest frequency task not in cooldown.
- If no task is available, CPU idles.
- Update frequencies and cooldown queue until all tasks are done.
💡 The challenge is managing cooldown and choosing tasks greedily each time, which is complex to implement and slow.
from collections import Counter, deque
def leastInterval(tasks, n):
freq = Counter(tasks)
time = 0
cooldown = deque() # stores pairs (task, ready_time)
while freq or cooldown:
time += 1
# Release tasks from cooldown if ready_time <= current time
while cooldown and cooldown[0][1] <= time:
task = cooldown.popleft()[0]
freq[task] = freq.get(task, 0) + 1
if freq:
# Pick task with highest frequency
task = max(freq, key=freq.get)
freq[task] -= 1
if freq[task] == 0:
del freq[task]
cooldown.append((task, time + n + 1))
return time
# Example usage
if __name__ == '__main__':
print(leastInterval(['A','A','A','B','B','B'], 2)) # Output: 8
Line Notes
freq = Counter(tasks)Count how many times each task appears to know frequencies.
time = 0Initialize the time counter to track total units.
cooldown = deque()Use a queue to track tasks currently cooling down with their ready times.
while freq or cooldown:Continue until all tasks are done and no tasks are cooling down.
time += 1Increment time at each iteration representing one unit of CPU time.
while cooldown and cooldown[0][1] <= time:Release all tasks whose cooldown has expired and are ready to be scheduled again.
task = cooldown.popleft()[0]Remove the task from cooldown and add it back to frequency map.
task = max(freq, key=freq.get)Pick the task with the highest remaining frequency to execute next.
freq[task] -= 1Decrease the frequency of the executed task.
if freq[task] == 0: del freq[task]Remove the task from frequency map if completed.
cooldown.append((task, time + n + 1))Add the executed task to cooldown with its next available time.
import java.util.*;
public class Solution {
public int leastInterval(char[] tasks, int n) {
Map<Character, Integer> freq = new HashMap<>();
for (char t : tasks) freq.put(t, freq.getOrDefault(t, 0) + 1);
Queue<Map.Entry<Character, Integer>> cooldown = new LinkedList<>();
int time = 0;
while (!freq.isEmpty() || !cooldown.isEmpty()) {
time++;
// Release tasks from cooldown if ready_time <= current time
while (!cooldown.isEmpty() && cooldown.peek().getValue() <= time) {
char task = cooldown.poll().getKey();
freq.put(task, freq.getOrDefault(task, 0) + 1);
}
if (!freq.isEmpty()) {
char task = Collections.max(freq.entrySet(), Map.Entry.comparingByValue()).getKey();
freq.put(task, freq.get(task) - 1);
if (freq.get(task) == 0) freq.remove(task);
cooldown.offer(new AbstractMap.SimpleEntry<>(task, time + n + 1));
}
}
return time;
}
public static void main(String[] args) {
Solution sol = new Solution();
System.out.println(sol.leastInterval(new char[]{'A','A','A','B','B','B'}, 2)); // 8
}
}
Line Notes
Map<Character, Integer> freq = new HashMap<>()Count frequencies of each task.
Queue<Map.Entry<Character, Integer>> cooldown = new LinkedList<>()Track tasks in cooldown with their ready times.
while (!freq.isEmpty() || !cooldown.isEmpty())Loop until all tasks are done and cooldown is empty.
time++Increment time unit by unit.
while (!cooldown.isEmpty() && cooldown.peek().getValue() <= time)Release all tasks whose cooldown has expired and are ready to be scheduled again.
char task = cooldown.poll().getKey()Retrieve task ready to be scheduled again.
char task = Collections.max(freq.entrySet(), Map.Entry.comparingByValue()).getKey()Pick task with highest frequency to execute.
freq.put(task, freq.get(task) - 1)Decrease frequency after execution.
if (freq.get(task) == 0) freq.remove(task)Remove task if completed.
cooldown.offer(new AbstractMap.SimpleEntry<>(task, time + n + 1))Add task to cooldown with next available time.
#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
#include <algorithm>
using namespace std;
int leastInterval(vector<char>& tasks, int n) {
unordered_map<char, int> freq;
for (char t : tasks) freq[t]++;
queue<pair<char,int>> cooldown;
int time = 0;
while (!freq.empty() || !cooldown.empty()) {
time++;
// Release tasks from cooldown if ready_time <= current time
while (!cooldown.empty() && cooldown.front().second <= time) {
char task = cooldown.front().first;
cooldown.pop();
freq[task]++;
}
if (!freq.empty()) {
auto it = max_element(freq.begin(), freq.end(), [](auto &a, auto &b){ return a.second < b.second; });
char task = it->first;
freq[task]--;
if (freq[task] == 0) freq.erase(task);
cooldown.push({task, time + n + 1});
}
}
return time;
}
int main() {
vector<char> tasks = {'A','A','A','B','B','B'};
int n = 2;
cout << leastInterval(tasks, n) << endl; // 8
return 0;
}
Line Notes
unordered_map<char, int> freq;Count frequency of each task.
queue<pair<char,int>> cooldown;Track tasks in cooldown with their ready times.
while (!freq.empty() || !cooldown.empty())Loop until all tasks are done and cooldown is empty.
time++;Increment time unit by unit.
while (!cooldown.empty() && cooldown.front().second <= time)Release all tasks whose cooldown has expired and are ready to be scheduled again.
char task = cooldown.front().first; cooldown.pop();Retrieve task ready to be scheduled again.
auto it = max_element(freq.begin(), freq.end(), ...);Find task with highest frequency to execute.
freq[task]--; if (freq[task] == 0) freq.erase(task);Decrease frequency and remove if done.
cooldown.push({task, time + n + 1});Add task to cooldown with next available time.
function leastInterval(tasks, n) {
const freq = new Map();
for (const t of tasks) freq.set(t, (freq.get(t) || 0) + 1);
const cooldown = [];
let time = 0;
while (freq.size > 0 || cooldown.length > 0) {
time++;
// Release tasks from cooldown if ready_time <= current time
while (cooldown.length > 0 && cooldown[0][1] <= time) {
const [task] = cooldown.shift();
freq.set(task, (freq.get(task) || 0) + 1);
}
if (freq.size > 0) {
let maxTask = null, maxCount = -1;
for (const [task, count] of freq.entries()) {
if (count > maxCount) {
maxCount = count;
maxTask = task;
}
}
freq.set(maxTask, maxCount - 1);
if (freq.get(maxTask) === 0) freq.delete(maxTask);
cooldown.push([maxTask, time + n + 1]);
}
}
return time;
}
// Example usage
console.log(leastInterval(['A','A','A','B','B','B'], 2)); // 8
Line Notes
const freq = new Map();Count frequency of each task.
const cooldown = [];Array to track tasks in cooldown with ready times.
while (freq.size > 0 || cooldown.length > 0)Loop until all tasks are done and cooldown is empty.
time++;Increment time unit by unit.
while (cooldown.length > 0 && cooldown[0][1] <= time)Release all tasks whose cooldown has expired and are ready to be scheduled again.
const [task] = cooldown.shift();Retrieve task ready to be scheduled again.
for (const [task, count] of freq.entries())Find task with highest frequency to execute.
freq.set(maxTask, maxCount - 1);Decrease frequency after execution.
if (freq.get(maxTask) === 0) freq.delete(maxTask);Remove task if completed.
cooldown.push([maxTask, time + n + 1]);Add task to cooldown with next available time.
TimeO(m * t) where m is number of unique tasks and t is total time units
SpaceO(m + n) for frequency map and cooldown queue
At each time unit, we scan frequencies to pick max task, which is costly for large inputs.
💡 For 100 tasks and 2 cooldown, this approach might do thousands of operations, which is inefficient.
Interview Verdict: TLE / Inefficient for large inputs
This approach is too slow for large inputs but helps understand the problem and constraints.