题目链接: https://leetcode.com/problems/task-scheduler
You are given an array of CPU
tasks
, each represented by letters A to Z, and a cooling time,n
. Each cycle or interval allows the completion of one task. Tasks can be completed in any order, but there's a constraint: identical tasks must be separated by at leastn
intervals due to cooling time.Return the minimum number of intervals required to complete all tasks.
函数定义:
class Solution {
public:
int leastInterval(vector<char>& tasks, int n) {}
};
这是一道典型的贪心算法题目。容易想到,CPU 执行的最小时间取决于频率最高的任务 。
假设 的频率为 ,相同任务之间的间隔(interval)为 ,那么将 全部执行完需要的时间为: 其中 是因为最后一个 执行完毕后不需要再添加 个时间,只添加 个时间即可。
此时产生的空位数量 。
假设 只有一个,那么剩余任务只需要全部放在两个 执行的间隙当中即可。假设剩余任务的数量为 :
- 有些情况下 ,例如当任务列表为 , 时,容易得到 而 。这种情况下的一种最小调度序列为 。
- 有些情况下 ,例如当任务列表为 , 时,容易得到 而 。这种情况下的一种最小调度序列为 。
容易看出情况 1 时 装得下剩余的任务,因此执行最小时间为 ;而情况 2 时 不够用,需要在间隔(interval)当中加入超过 的任务,因此执行最小时间为 。因此执行最小时间的计算公式为: 值得注意的是,情况 2 下没有比加到间隔(interval)当中更优的调度方式。
但是,如果 有 个,那么把所有任务都执行完需要的最小时间是多少呢?
相比 只有一个的情况,我们需要在调度序列最后添加更多的时间。
此时,每个 都首先消耗 个 ,在调度序列末尾,需要再消耗一个时间执行最后的 ,即 。如果 不足以 以及其他 消耗,执行最小时间仍然是 。因此执行最小时间的计算公式为: 举例来说,如果 为 ,
若 ,则
- 首先根据 找到 :;
- 继续令下一个 消耗 :,注意最后 多消耗了一个时间;
- 不足以 的消耗,因此执行最小时间为 。
若 ,则
首先根据 找到 :;
继续令下一个 消耗 :,注意最后 多消耗了一个时间;
足以 的消耗,因此执行最小时间为 。
把以上公式写成代码,就得到了题解:
class Solution {
public:
int leastInterval(vector<char>& tasks, int n) {
const int TASK_COUNT = tasks.size();
vector<int> taskFrequency(26, 0);
int maxTaskFrequency = 0;
for (char task : tasks) {
taskFrequency[task - 'A']++;
maxTaskFrequency = std::max(maxTaskFrequency, taskFrequency[task - 'A']);
}
const int taskWithMaxFrequencyCount =
std::count_if(taskFrequency.cbegin(), taskFrequency.cend(),
[maxTaskFrequency](auto element) {
return element == maxTaskFrequency;
});
return std::max(TASK_COUNT, (maxTaskFrequency - 1) * (n + 1) +
taskWithMaxFrequencyCount);
}
};