给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。在任何一个单位时间,CPU 可以完成一个任务,或者处于待命状态。
然而,两个 相同种类 的任务之间必须有长度为整数 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。
你需要计算完成所有任务所需要的 最短时间 。
示例 1:
输入:tasks = ["A","A","A","B","B","B"], n = 2
输出:8
解释:A -> B -> (待命) -> A -> B -> (待命) -> A -> B
在本示例中,两个相同类型任务之间必须间隔长度为 n = 2 的冷却时间,而执行一个任务只需要一个单位时间,所以中间出现了(待命)状态。
示例 2:
输入:tasks = ["A","A","A","B","B","B"], n = 0
输出:6
解释:在这种情况下,任何大小为 6 的排列都可以满足要求,因为 n = 0
["A","A","A","B","B","B"]
["A","B","A","B","A","B"]
["B","B","B","A","A","A"]
...
诸如此类
示例 3:
输入:tasks = ["A","A","A","A","A","A","B","C","D","E","F","G"], n = 2
输出:16
解释:一种可能的解决方案是:
A -> B -> C -> A -> D -> E -> A -> F -> G -> A -> (待命) -> (待命) -> A -> (待命) -> (待命) -> A
首先我通俗的解释一下这道题,每一个字母代表的是一种任务,比如["A","A","A","B","B","B"],A可能代表吃饭,B代表睡觉,n代表做完这件事隔多久以后才能再做这件事,当n=2时,代表每隔两个时间周期才能再做这件事,假定每件事运行周期1,也就是1的时候吃了饭A,下次吃饭只能是3的时刻,而期间我们可以做别的事,比如B睡觉。那就变成了,吃饭,睡觉,待命状态,吃饭,睡觉,待命状态...
所以假定我们把n当做一个周期,那么这个周期内我们可以做n+1件事。而我们将需要做的次数最多的事的次数,当做我们需要做多少个周期。A的个数为3时,我们需要三个周期。
我们以["A","A","A","A","A","A","B","B","B","B","B","B","C","C","D","D","D","F","F"],n=2为例:
需要运行次数最多的是A=6,时间周期为n=2,那我们以每一层容积为3,高度为6建立一个桶
假定我们没有其他任务的情况下,我们需要执行的时间为(6-1)*3+1=16,因为最后一层当我们之行完A后即可结束,不再需要进行后面的等待了。
而当我们逐渐向其中添加新的任务时
当出现其余任务有和执行最多次任务所执行的次数相同时,我们便会在总执行任务时间上+1,所以我们要知道有多少种任务执行的次数和我们所记录的执行最多次数的任务的次数相同,而像C任务这种次数较少的任务,并不会占用更多的任务时间,只会填充待命状态。我们只需要记录多执行的那次B即可(6-1)*3+2=17
前面两种情况,总结起来:总排队时间 = (桶个数 - 1) * (n + 1) + 最后一桶的任务数
而当冷却时间短,所需要执行的任务多时,我们需要怎么处理
此时我们又多执行了三次D,但是仍没有超过之前的待命状态,所以总执行时间不变。但是如果任务继续增加呢。
这时我们并不需要添加新的桶,因为添加新的桶可能意味着我们还需要更多的待命状态,我们只需要扩充之前的桶即可。这样插入即最小化了需要增加的时间,也满足的后加入的任务的待命状态。
插入前:ABC | ABC | ABD | ABD | ABD | AB 插入后:ABCF | ABCF | ABD | ABD | ABD | AB
我们在第一个、第二个桶子里插入了任务F,不难发现无论再继续插入多少任务,我们都可以类似处理,而且新插入元素肯定满足冷却要求。
所以总结下来:
- 记录最大任务数量 N,看一下任务数量并列最多的任务有多少个,即最后一个桶子的任务数 X,计算
NUM1=(N-1)*(n+1)+x NUM2=tasks.size()- 比较两者的最大值
如果NUM2更大,则是最后一张图,在常规时间呗填充满的情况下,多出了的任务可以直接进行扩充,而所需时间正好为数组的长度,并不存在需要填充的待命状态。而如果NUM1更大则证明没有需要扩充的桶,有可能存在待命状态。
var leastInterval = function (tasks, n) {
const arr = new Array(26).fill(0);
const len = tasks.length
for (let i = 0; i < tasks.length; i++) {
const char = tasks[i]
arr[char.charCodeAt() - "A".charCodeAt()]++
}
for (let i = 0; i < arr.length;) {
const num = arr[i];
if (num == 0) {
arr.splice(i, 1)
} else {
i++
}
}
arr.sort((a, b) => b - a)
console.log(arr);
let cnt = 1;
while (cnt < arr.length && arr[cnt] === arr[0]) {
cnt++
}
return Math.max(len, cnt + (n + 1) * (arr[0] - 1))
};
复杂度分析
- 时间复杂度 O(nlogn)
- 空间复杂度 O(1)