Medium
题目描述
给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表,用字母 A 到 Z 表示,以及一个冷却时间 n。每个 CPU 时间片可以完成一个任务,或者处于待命状态。
相同类型的任务之间必须有长度为整数 n 的冷却时间,因此至少有连续 n 个时间片用来执行其他任务,或者处于待命状态。
你需要计算完成所有任务所需要的最短时间。
示例 1:
输入:tasks = ["A","A","A","B","B","B"], n = 2
输出:8
解释:A -> B -> idle -> A -> B -> idle -> A -> B
在完成任务 A 之后,你必须等待两个间隔。对任务 B 同样如此。
在第 3 个间隔,A 和 B 都不能完成,所以你需要待命。
在第 4 个间隔,你可以再次开始任务 A,因为它已经等待了 2 个间隔。
示例 2:
输入:tasks = ["A","C","A","B","D","B"], n = 1
输出:6
解释:一种可能的序列是:A -> B -> C -> D -> A -> B
由于冷却间隔为 1,你可以在一个其他任务后重复一个任务。
示例 3:
输入:tasks = ["A","A","A", "B","B","B"], n = 3
输出:10
解释:一种可能的序列是:A -> B -> idle -> idle -> A -> B -> idle -> idle -> A -> B
只有两种任务类型,A 和 B,它们需要被 3 个间隔分开。这导致在这些任务的重复之间有两次待命。
提示:
1 <= tasks.length <= 10^4tasks[i]是大写英文字母0 <= n <= 100
解题思路
解题思路
这道题有两种主要思路:
思路一:数学公式法(推荐)
观察规律可以发现,最终时间主要由出现次数最多的任务决定。设最高频率为 maxCount,有 countOfMax 个任务达到这个频率。
核心观察:
- 出现次数最多的任务之间必须间隔
n个时间片 - 可以将时间轴按照最高频任务分割成若干块,每块长度为
n+1 - 最后一块可能不满
n+1,只需要放置剩余的最高频任务
计算公式:max(tasks.length, (maxCount-1) * (n+1) + countOfMax)
思路二:优先队列模拟法
使用最大堆维护任务频率,每次取出频率最高的可执行任务。通过队列记录冷却中的任务,时间到了再重新加入堆中。这种方法更直观但时间复杂度较高。
数学公式法更优雅高效,是首选解法。当任务种类很多且分布均匀时,不需要等待,直接返回任务总数;当某些任务频率很高时,需要考虑冷却等待时间。
代码实现
class Solution {
public:
int leastInterval(vector<char>& tasks, int n) {
unordered_map<char, int> freq;
for (char task : tasks) {
freq[task]++;
}
int maxCount = 0;
for (auto& p : freq) {
maxCount = max(maxCount, p.second);
}
int countOfMax = 0;
for (auto& p : freq) {
if (p.second == maxCount) {
countOfMax++;
}
}
return max((int)tasks.size(), (maxCount - 1) * (n + 1) + countOfMax);
}
};
class Solution:
def leastInterval(self, tasks: List[str], n: int) -> int:
from collections import Counter
freq = Counter(tasks)
max_count = max(freq.values())
count_of_max = sum(1 for count in freq.values() if count == max_count)
return max(len(tasks), (max_count - 1) * (n + 1) + count_of_max)
public class Solution {
public int LeastInterval(char[] tasks, int n) {
var freq = new Dictionary<char, int>();
foreach (char task in tasks) {
freq[task] = freq.GetValueOrDefault(task, 0) + 1;
}
int maxCount = freq.Values.Max();
int countOfMax = freq.Values.Count(count => count == maxCount);
return Math.Max(tasks.Length, (maxCount - 1) * (n + 1) + countOfMax);
}
}
/**
* @param {character[]} tasks
* @param {number} n
* @return {number}
*/
var leastInterval = function(tasks, n) {
const freq = new Map();
let maxFreq = 0;
for (const task of tasks) {
freq.set(task, (freq.get(task) || 0) + 1);
maxFreq = Math.max(maxFreq, freq.get(task));
}
let maxFreqCount = 0;
for (const count of freq.values()) {
if (count === maxFreq) {
maxFreqCount++;
}
}
const minIntervals = (maxFreq - 1) * (n + 1) + maxFreqCount;
return Math.max(minIntervals, tasks.length);
};
复杂度分析
| 复杂度类型 | 数学公式法 |
|---|---|
| 时间复杂度 | O(m),其中 m 是任务种类数,最多26种 |
| 空间复杂度 | O(m),用于存储任务频率 |
相关题目
. Reorganize String (Medium)
. Task Scheduler II (Medium)
. Generate Schedule (Medium)