题目描述
给你一个用字符数组 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
提示:
- 1 <= task.length <= 104
- tasks[i] 是大写英文字母
- n 的取值范围为 [0, 100]
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ta… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
-
统计出任务种类,及其数量
-
while遍历,每次选择能立刻执行且剩余执行次数最多的,就是当前要执行的任务
-
如果所有任务都不可立即执行,就是待机次数
-
如果有能执行的,就选出次数剩余最多的,把次数减1,并把等待时间设置为n
-
其余等待时间大于0的任务,等待时间都减去 1
-
在有任务执行的回合,在任务次数减1后判断,剩余任务次数如果等于0的话,就把任务移除
-
循环结束的条件就是,任务数减为0
-
最后返回执行过循环的次数就是需要的时间
代码
/**
* @param {character[]} tasks
* @param {number} n
* @return {number}
*/
var leastInterval = function(tasks, n) {
if(n===0) return tasks.length;
let taskTime=_.countBy(tasks);//每个字母出现的次数
let keys=Object.keys(taskTime).length;//字母的种类数量
let times=new Array(keys).fill(0);//能执行任务的倒计时,初始为0,能立刻执行
let values=Object.values(taskTime);//剩余次数的数组
// 当每种字母次数扣完时移出这个字母,当所有的字母次数扣完就是完成了所有任务
let result=0;//结果
while(keys>0){
result++;
//我们每次需要找出那个,等待时间为0,且剩余次数最多的字母来扣减,等待时间都不为0就不扣减
let best=-1;
for (let i=0;i<keys;i++){
if(times[i]===0){//能执行的
if(best===-1||values[i]>values[best]){
//选出能执行的里面最大的那个index
best=i;
}
}else if(times[i]>0){
times[i]-=1;
}
}
//如果best=-1就是所有的都还不能执行,就是待机时间不做处理
//如果不是-1,就要给选中的任务次数减1,并把待机时间设置为n
if(best!==-1){
values[best]-=1;
times[best]=n;
if(values[best]===0){
//如果某个种类的任务已经执行完毕,就给他从任务列表删除,如果所有任务删除就到了循环结束的时候
values.splice(best,1);
times.splice(best,1);
keys-=1;
}
}
}
return result;
};