621. Task Scheduler
Problem Description
Given a characters array tasks, representing the tasks a CPU needs to do, where each letter represents a different task. Tasks could be done in any order. Each task is done in one unit of time. For each unit of time, the CPU could complete either one task or just be idle.
However, there is a non-negative integer n that represents the cooldown period between two same tasks (the same letter in the array), that is that there must be at least n units of time between any two same tasks.
Return the least number of units of time that the CPU will take to finish all the given tasks.
Examples:
Example 1:
Input: tasks = ["A","A","A","B","B","B"], n = 2 Output: 8 Explanation: A -> B -> idle -> A -> B -> idle -> A -> B There is at least 2 units of time between any two same tasks.
Example 2:
Input: tasks = ["A","A","A","B","B","B"], n = 0 Output: 6 Explanation: On this case any permutation of size 6 would work since n = 0. ["A","A","A","B","B","B"] ["A","B","A","B","A","B"] ["B","B","B","A","A","A"] etc.
Example 3:
Input: tasks = ["A","A","A","A","A","A","B","C","D","E","F","G"], n = 2 Output: 16 Explanation: One possible solution is A -> B -> C -> A -> D -> E -> A -> F -> G -> A -> idle -> idle -> A -> idle -> idle -> A
Constraints:
1 <= task.length <= 10⁴tasks[i]is upper-case English letter0 <= n <= 100
Solution
Python Solution
class Solution:
def leastInterval(self, tasks: List[str], n: int) -> int:
# Count frequency of each task
freq = Counter(tasks)
max_freq = max(freq.values())
# Count how many tasks have the maximum frequency
max_freq_tasks = sum(1 for f in freq.values() if f == max_freq)
# Calculate minimum intervals needed
min_intervals = (max_freq - 1) * (n + 1) + max_freq_tasks
return max(min_intervals, len(tasks))
Time Complexity: O(N)
Where N is the number of tasks.
Space Complexity: O(1)
Since we only store at most 26 characters (uppercase English letters).
Explanation:
- Count the frequency of each task
- Find the task with maximum frequency (max_freq)
- Count tasks with maximum frequency (max_freq_tasks)
- Calculate minimum intervals using formula: (max_freq - 1) * (n + 1) + max_freq_tasks
- Return maximum of calculated intervals and total tasks
Java Solution
class Solution {
public int leastInterval(char[] tasks, int n) {
// Count frequency of each task
int[] freq = new int[26];
for (char task : tasks) {
freq[task - 'A']++;
}
// Find maximum frequency
int maxFreq = 0;
for (int f : freq) {
maxFreq = Math.max(maxFreq, f);
}
// Count tasks with maximum frequency
int maxFreqTasks = 0;
for (int f : freq) {
if (f == maxFreq) maxFreqTasks++;
}
// Calculate minimum intervals needed
int minIntervals = (maxFreq - 1) * (n + 1) + maxFreqTasks;
return Math.max(minIntervals, tasks.length);
}
}
Alternative Solution using PriorityQueue:
class Solution {
public int leastInterval(char[] tasks, int n) {
int[] freq = new int[26];
for (char task : tasks) {
freq[task - 'A']++;
}
PriorityQueue pq = new PriorityQueue<>((a, b) -> b - a);
for (int f : freq) {
if (f > 0) pq.offer(f);
}
int time = 0;
while (!pq.isEmpty()) {
List temp = new ArrayList<>();
int i = 0;
while (i <= n && !pq.isEmpty()) {
int count = pq.poll();
if (count > 1) temp.add(count - 1);
time++;
i++;
}
pq.addAll(temp);
if (!pq.isEmpty() && i <= n) time += (n - i + 1);
}
return time;
}
}
C++ Solution
class Solution {
public:
int leastInterval(vector& tasks, int n) {
vector freq(26, 0);
for (char task : tasks) {
freq[task - 'A']++;
}
int maxFreq = *max_element(freq.begin(), freq.end());
int maxFreqTasks = count(freq.begin(), freq.end(), maxFreq);
int minIntervals = (maxFreq - 1) * (n + 1) + maxFreqTasks;
return max(minIntervals, (int)tasks.size());
}
};
Alternative Solution using Priority Queue:
class Solution {
public:
int leastInterval(vector& tasks, int n) {
vector freq(26, 0);
for (char task : tasks) {
freq[task - 'A']++;
}
priority_queue pq;
for (int f : freq) {
if (f > 0) pq.push(f);
}
int time = 0;
while (!pq.empty()) {
vector temp;
int i = 0;
while (i <= n && !pq.empty()) {
int count = pq.top(); pq.pop();
if (count > 1) temp.push_back(count - 1);
time++;
i++;
}
for (int count : temp) pq.push(count);
if (!pq.empty() && i <= n) time += (n - i + 1);
}
return time;
}
};
JavaScript Solution
/**
* @param {character[]} tasks
* @param {number} n
* @return {number}
*/
var leastInterval = function(tasks, n) {
// Count frequency of each task
const freq = new Array(26).fill(0);
for (const task of tasks) {
freq[task.charCodeAt(0) - 'A'.charCodeAt(0)]++;
}
// Find maximum frequency
const maxFreq = Math.max(...freq);
// Count tasks with maximum frequency
const maxFreqTasks = freq.filter(f => f === maxFreq).length;
// Calculate minimum intervals needed
const minIntervals = (maxFreq - 1) * (n + 1) + maxFreqTasks;
return Math.max(minIntervals, tasks.length);
};
Alternative Solution using Map:
var leastInterval = function(tasks, n) {
const freq = new Map();
for (const task of tasks) {
freq.set(task, (freq.get(task) || 0) + 1);
}
const maxFreq = Math.max(...freq.values());
const maxFreqTasks = Array.from(freq.values()).filter(f => f === maxFreq).length;
return Math.max((maxFreq - 1) * (n + 1) + maxFreqTasks, tasks.length);
};
Performance Considerations:
- Array-based solution is more memory efficient than Map-based solution
- For small n, the simple formula approach is faster than simulation
- Priority Queue solution is useful when you need to handle dynamic task scheduling
C# Solution
public class Solution {
public int LeastInterval(char[] tasks, int n) {
int[] freq = new int[26];
foreach (char task in tasks) {
freq[task - 'A']++;
}
int maxFreq = freq.Max();
int maxCount = freq.Count(f => f == maxFreq);
return Math.Max(tasks.Length, (maxFreq - 1) * (n + 1) + maxCount);
}
}
Alternative Solution using PriorityQueue:
public class Solution {
public int LeastInterval(char[] tasks, int n) {
int[] freq = new int[26];
foreach (char task in tasks) {
freq[task - 'A']++;
}
var pq = new PriorityQueue();
foreach (int f in freq) {
if (f > 0) pq.Enqueue(f, -f); // Use negative for max heap
}
int time = 0;
while (pq.Count > 0) {
var temp = new List();
int i = 0;
while (i <= n && pq.Count > 0) {
int count = pq.Dequeue();
if (count > 1) temp.Add(count - 1);
time++;
i++;
}
foreach (int count in temp) {
pq.Enqueue(count, -count);
}
if (pq.Count > 0 && i <= n) time += (n - i + 1);
}
return time;
}
}
Implementation Notes:
- First solution uses LINQ for cleaner code
- PriorityQueue solution available in .NET 6+ for optimal performance
- Both solutions have O(n) time complexity
- PriorityQueue solution uses more memory but simulates actual scheduling