Task Scheduler

The problem description can be found in LeetCode.

Approach

A greedy approach can be used to solve this problem.

By deriving some examples, we can prove that the best way to start would be to select the most frequent tasks and then continue with the other ones.

tasks = ["A", "A", "A", "B"]
n = 2

If we select B first we would have the sequence:

B -> A -> idle -> idle -> A -> idle -> idle -> A -> idle -> idle

However, if we select A first:

A -> B -> A -> idle -> idle -> A

Once the most frequent task is completed, we can decrease its number of occurrences by one and still use it for the next iteration if the number is not 0.

An efficient data structure that allows this is the Heap.

Solution

import heapq
from typing import List


class Solution:
    def leastInterval(self, tasks: List[str], n: int) -> int:
        counter = self.get_chars_counter(tasks)

        heap = [-occ for occ in counter if occ > 0]
        heapq.heapify(heap)

        ans = 0
        while heap:
            remained_tasks = []
            completed_tasks = 0

            for _ in range(n + 1):
                if not heap:
                    break

                completed_tasks += 1

                occ = -heapq.heappop(heap) - 1
                if occ > 0:
                    remained_tasks.append(-occ)

            for task in remained_tasks:
                heapq.heappush(heap, task)

            ans += completed_tasks if not heap else n + 1

        return ans

    def get_chars_counter(self, tasks: List[str]) -> List[int]:
        m = [0] * 26

        for task in tasks:
            assert isinstance(task, str)
            assert len(task) == 1

            idx = ord(task) - ord("A")
            m[idx] += 1

        return m

Complexity

  • Time:
  • Space:

Where is the size of the tasks list.