一、题目描述
给你一个用字符数组 tasks
表示的 CPU 需要执行的任务列表,用字母 A 到 Z 表示,以及一个冷却时间 n
。每个周期或时间间隔允许完成一项任务。任务可以按任何顺序完成,但有一个限制:两个 相同种类 的任务之间必须有长度为 n
的冷却时间。
返回完成所有任务所需要的 最短时间间隔 。
示例 1:
输入:tasks = ["A","A","A","B","B","B"], n = 2
输出:8
解释:
在完成任务 A 之后,你必须等待两个间隔。对任务 B 来说也是一样。在第 3 个间隔,A 和 B 都不能完成,所以你需要待命。在第 4 个间隔,由于已经经过了 2 个间隔,你可以再次执行 A 任务。
示例 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^4
tasks[i]
是大写英文字母0 <= n <= 100
二、解题思路
- 统计每个任务出现的次数,可以使用一个长度为26的数组来记录,因为任务只有A到Z共26种。
- 找出出现次数最多的任务,假设其出现次数为maxCount。
- 计算最短时间间隔,最短时间间隔至少为 (maxCount - 1) * (n + 1) + 1。这是因为最频繁的任务之间需要有n个冷却时间,而最频繁的任务可以放在序列的开始和结束位置。
- 遍历统计数组,找出有多少个任务的出现次数等于maxCount,记为maxCountTasks。
- 如果maxCountTasks大于1,那么最短时间间隔就是任务总数,因为最频繁的任务之间至少有一个冷却时间,但如果有多个任务出现次数相同,那么它们可以交替执行,不会有空闲时间。
- 如果maxCountTasks小于等于1,那么最短时间间隔是步骤3计算的结果和任务总数之间的较大值,因为可能存在空闲时间。
三、具体代码
class Solution {
public int leastInterval(char[] tasks, int n) {
// 步骤1:统计每个任务出现的次数
int[] taskCounts = new int[26];
for (char task : tasks) {
taskCounts[task - 'A']++;
}
// 步骤2:找出出现次数最多的任务
int maxCount = 0;
for (int count : taskCounts) {
maxCount = Math.max(maxCount, count);
}
// 步骤3:计算最短时间间隔
int intervals = (maxCount - 1) * (n + 1);
// 步骤4:找出有多少个任务的出现次数等于maxCount
int maxCountTasks = 0;
for (int count : taskCounts) {
if (count == maxCount) {
maxCountTasks++;
}
}
// 步骤5和6:返回最短时间间隔
return Math.max(intervals + maxCountTasks, tasks.length);
}
}
四、时间复杂度和空间复杂度
1. 时间复杂度
- 统计每个任务出现的次数:我们需要遍历整个
tasks
数组,这个数组的大小是m
,所以这一步的时间复杂度是O(m)。 - 找出出现次数最多的任务:我们需要遍历一个固定大小的数组
taskCounts
,它的大小是26,所以这一步的时间复杂度是O(1),因为遍历一个固定大小的数组的时间复杂度是常数。 - 再次遍历
taskCounts
数组来找出有多少个任务的出现次数等于maxCount
:这一步的时间复杂度同样是O(1)。
综上所述,整个算法的时间复杂度是O(m),因为O(m)和O(1)相加,时间复杂度由O(m)主导。
2. 空间复杂度
taskCounts
数组:这个数组的大小是固定的,为26,所以它占用的空间是O(1)。- 其他变量:
maxCount
、intervals
、maxCountTasks
等都是常数个变量,它们占用的空间是O(1)。
因此,整个算法的空间复杂度是O(1),因为算法使用的额外空间不随输入规模tasks
的大小变化。
五、总结知识点
-
数组的使用:
- 使用数组
taskCounts
来统计每个任务出现的次数。 - 遍历数组来找出最大值和特定条件下的元素数量。
- 使用数组
-
ASCII码操作:
- 通过
task - 'A'
将字符转换为数组索引,这是因为大写字母A到Z在ASCII码表中是连续的。
- 通过
-
循环和条件判断:
- 使用
for
循环来遍历任务数组tasks
和统计数组taskCounts
。 - 使用
if
语句来判断任务的出现次数是否等于最大出现次数。
- 使用
-
基本数学运算:
- 使用
Math.max
函数来找出最大值。 - 使用乘法和加法来计算最短时间间隔。
- 使用
-
算法逻辑:
- 实现了一个贪心算法,通过计算最频繁任务的间隔来确定最短时间间隔。
- 考虑到最频繁任务之间的冷却时间,以及可能存在的空闲时间。
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。