[路飞]_算法_ 任务调度器

135 阅读2分钟

题目描述

给你一个用字符数组 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;
};