Skip to main content

Task Scheduler


Task Scheduler: 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 times that the CPU will take to finish all the given tasks.

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"]
...
And so on.

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^4
  • tasks[i] is upper-case English letter.
  • The integer n is in the range [0, 100].

Try this Problem on your own or check similar problems:

  1. Task Scheduler II
  2. Maximum Number of Weeks for Which You Can Work
  3. Reorganize String
Solution:
public int leastInterval(char[] tasks, int n) {
int[] map = new int[26];

int freqOfMostOcurringTask = 0;
int countOfMostOccuringTasks = 0;

for(char task : tasks) {
++map[task - 'A'];

if(freqOfMostOcurringTask == map[task - 'A']) {
++countOfMostOccuringTasks;
}
else if(freqOfMostOcurringTask < map[task - 'A']) {
freqOfMostOcurringTask = map[task - 'A'];
countOfMostOccuringTasks = 1;
}
}

int numberOfGaps = freqOfMostOcurringTask - 1;
int gapLength = n - (countOfMostOccuringTasks - 1);
int totalLengthofGaps = numberOfGaps * gapLength;
int remainingTasks = tasks.length - freqOfMostOcurringTask * countOfMostOccuringTasks;
int idles = Math.max(0, totalLengthofGaps - remainingTasks);

return tasks.length + idles;
}

Time/Space Complexity:
  • Time Complexity: O(n)
  • Space Complexity: O(1)

Explanation:

If you look at example it will become obvious that the best task scheduling is the greedy one, in other words arranging the most frequent tasks first and then filling the gaps with remaining tasks. To count the frequency of tasks since tasks are only upper-case English letter, we only need to create array of 26 letters to keep the count. We iterate over the tasks and count their frequency each time checking if have a new most frequent task or if the current task has the same frequency as the most frequent task (which also makes it the most frequent task). Then to calculate the number of idles (spaces we cannot fill with tasks) we do the following:

  • If you have 3 occurrences of most frequent task, you need 2 gaps between those 3 occurrences (e.g. A gap A gap A).
  • To calculate the gap length, we place all of tasks with highest frequency countOfMostOccuringTasks (we subtract one since that's our A from the previous example), and what we are left is the number of spaces we have to fill to have n tasks in between.
  • totalLengthofGaps will just be the length of one gap gapLength multiplied with total number of gaps numberOfGaps.
  • To get number of remaining task (tasks with lower frequency than the ones with highest occurrence frequency) we just subtract number of tasks with highest frequency from the total number of tasks.
  • To get number of idles (spaces we cannot fill with tasks) we subtract the remainingTasks from the totalLengthofGaps.
  • Finally, we add the number of idles to the total number of tasks (each task will execute) and return it as our final result.