题目
621. 任务调度器
给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。在任何一个单位时间,CPU 可以完成一个任务,或者处于待命状态。
然而,两个 相同种类 的任务之间必须有长度为整数 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。
你需要计算完成所有任务所需要的 最短时间 。
思路:
这题首先要分析出,有几种场景,模糊分析如下
场景1:任务种类比较少,冷却时间比较长,那么总时间,其实是由数量最多的任务决定的,这种情况不管总任务有多少,都会有消耗一些时间在冷却上。
场景2:任务种类比较多,冷却时间比较短,那么总时间,是由任务总数量决定的
我一开始钻进了一个坑,一直在寻找这两种情况的边界条件,算了很久,发现边界条件很难算,而且最后发现,其实这个边界条件并不重要。
下面我们结合图标来总结归纳一下具体的情况
1.假设只有一种任务A,冷却时间为2,
如下图
| A | - | - |
|---|---|---|
| A | - | - |
| A | - | - |
| A | x | x |
我们把每一行看作一轮任务,那么最后一轮执行完A后就结束了,后续的就不用计算冷却时间了
记A的数量为N,那么我们要进行N轮任务
总时间 == N * (n+1) - n
这里我们换一种思维和写法,方便后面的归纳总结
总时间为 (任务轮数N-1)*(每一轮的任务数n+1) + 最后一轮的任务数
即总时间 == (N-1) * (n+1) + 1
这里总时间为7
| A | - |
|---|---|
| A | - |
| A | - |
| A | x |
2.有多种任务,但冷却时间较久,n=2
这种情况,其实跟刚才上一种情况是一样的
记A的数量为N 总时间 == (N-1)*(n+1)+1,是10
| A | B | C |
|---|---|---|
| A | B | - |
| A | B | - |
| A | x | x |
3.那假设B再多一个呢,如下图
总时间其实就变成了(N-1)*(n+1)+2,也就是最后+的这个数,并不是固定的,而是数量最多的任务的种类
数量最多的任务的种类为 X
那么总时间 == (N-1)*(n+1)+X
| A | B | C |
|---|---|---|
| A | B | - |
| A | B | - |
| A | B | x |
4.假设C数量增多,则会继续去填满冷却时间, 直到C成为任务最多的任务,那么任务轮数会增多,总体的计算公式仍然是 总时间 == (N-1)*(n+1)+X
| C | A | B | |
|---|---|---|---|
C | A | B | |
C | A | B | |
C | A | B | |
C | x | x | x |
这个时候可以看到,冷却时间已经没有了,最后一轮的-不算冷却时间。
5.假设现在开始任务种类和数量又增多了,但是冷却时间不边,那么我们会按下面这情况执行
这个时候你会发现,刚才的公式行不通了, (N-1)*(n+1)+X = 13
而实际总时间 == 18
这就走进了开始说的场景2
这个时候由于任务种类特别多,把冷却时间占用完之后,就可以排到任意轮次里面去执行
这时候 总时间 == 任务总数量
| C | A | B | D | E |
|---|---|---|---|---|
| C | A | B | D | E |
| C | A | B | D | x |
| C | A | B | x | x |
| C | x | x | x | x |
我们仔细分析一下,不管怎么去排,有一点可以确认的是,所消耗时间一定是大于等于任务数量
总结来说,我们只需要计算这两种情况的时间,取大的那个即可,而并不需要去找到边界做判断
Math.max((N-1)\*(n+1)+X,tasks.length)
具体代码实现如下:
/**
* @param {character[]} tasks
* @param {number} n
* @return {number}
*/
var leastInterval = function(tasks, n) {
let typeArr = [];
let countArr = [];
let time;
// 把任务按类别归纳
for(let i=0;i<tasks.length;i++){
if(typeArr.indexOf(tasks[i]) == -1){
typeArr.push(tasks[i])
countArr.push(1)
}else{
let index = typeArr.indexOf(tasks[i])
countArr[index]++
}
}
/ 任务种类数量
let k = typeArr.length;
let maxTypeNum = Math.max(...countArr);
let x = 0
for(let i=0;i<countArr.length;i++){
if(countArr[i] == maxTypeNum){
x++;
}
}
let time1 = (maxTypeNum-1)*(n+1)+x;
let time2 = tasks.length;
time = Math.max(time1,time2);
return time;
};