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:
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:
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:
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 <= 10^4
tasks[i]
is an uppercase English letter.0 <= n <= 100
import heapq
from collections import Counter
def leastInterval(tasks, n):
# Count the frequency of each task
task_counts = Counter(tasks)
# Create a max heap to store the frequencies
max_heap = [-count for count in task_counts.values()]
heapq.heapify(max_heap)
time = 0
queue = [] # (available_time, task_count)
while max_heap or queue:
time += 1
# If there are tasks available, add them back to the max heap
if queue and queue[0][0] == time:
count = heapq.heappop(queue)[1]
heapq.heappush(max_heap, count)
# If there are tasks in the max heap, execute one
if max_heap:
count = heapq.heappop(max_heap)
count += 1 # Decrement the count (since it's negative)
if count != 0:
available_time = time + n + 1
heapq.heappush(queue, (available_time, count))
return time
# Example usage
tasks1 = ["A","A","A","B","B","B"]
n1 = 2
print(leastInterval(tasks1, n1)) # Output: 8
tasks2 = ["A","C","A","B","D","B"]
n2 = 1
print(leastInterval(tasks2, n2)) # Output: 6
tasks3 = ["A","A","A", "B","B","B"]
n3 = 3
print(leastInterval(tasks3, n3)) # Output: 10
Counter(tasks)
. This is essential for understanding how many times each task needs to be executed.max_heap
) is created to store the frequencies of the tasks. The frequencies are negated because Python's heapq
module implements a min heap. By negating the values, we can simulate a max heap.while
loop continues as long as there are tasks in the max_heap
or tasks waiting in the queue
. The time
variable keeps track of the current CPU interval.queue
is used to keep track of tasks that are冷却 down. If a task's冷却 down period is over (i.e., queue[0][0] == time
), it is added back to the max_heap
.max_heap
, the task with the highest frequency is executed. The count is decremented, and if the task still needs to be executed again, it is added to the queue
with its available time.[-3, -3]
time = 1
: Execute A. max_heap = [-3]
, queue = [(4, -2)]
time = 2
: Execute B. max_heap = []
, queue = [(4, -2), (5, -2)]
time = 3
: Idle. max_heap = []
, queue = [(4, -2), (5, -2)]
time = 4
: A becomes available. max_heap = [-2]
, queue = [(5, -2)]
time = 5
: B becomes available. max_heap = [-2]
, queue = [(6, -1)]
time = 6
: Execute A. max_heap = [-2]
, queue = [(6, -1)]
, new queue queue = [(6, -1), (9, -1)]
time = 7
: Execute B. max_heap = []
, queue = [(9, -1)]
time = 8
: Execute A. max_heap = []
, queue = []
O(T)
where T is the number of tasks.O(log K)
time, where K is the number of unique tasks. Thus, this part takes O(T log K)
time.O(T log K)
. Since K
is at most 26 (number of uppercase English letters), log K
is effectively constant. Therefore, the time complexity can be approximated as O(T)
.O(K)
, where K is the number of unique tasks (at most 26).O(K)
, storing the counts of each unique task.O(K)
.O(K)
. Again, since K
is at most 26, this can be considered O(1)
(constant space).tasks
list is empty, the function should return 0.n
is 0, it means there is no cooling period. In this case, the minimum time is simply the number of tasks.n
is very large compared to the number of tasks, there will be many idle slots. The algorithm correctly handles this by managing the queue
appropriately.