任务调度器算法(leetcode621)

题目描述如下:
任务调度器算法(leetcode621)_第1张图片
思路:
要想完成任务的时间最短,那么必须优先处理出现次数最多的任务(如果将次数多的任务留到最后,必然在每次任务之间留出大量的等待时间),因此我们可以以n+1个任务为一轮(保证同一种任务不出现在同一轮),每一轮按出现次数顺序从大到小执行,每完成一轮就重新排序依次,直到所有任务完成;
例如:AAABBBBC n=2
首先统计任务次数,然后排序得到 4 3 1
初始time=0
每一轮任务个数为3
第一轮 :从次数为4的任务开始,执行一次++time ,然后3执行依次,++time, 然后1执行依次,++time;
完成后再排序有 3 2

第二轮:次数为3的任务执行一次,++time, 次数为2的任务执行一次,++time,本轮找不到剩下可执行的任务,此时需等待一个单位时间,++time
完成后再排序有 2 1

第三轮:*依次类推。。。++time ,++time,++time(等待)
完成后再排序有 1

第四轮:++time (所有任务完成,不需要另外等待两个单位时间)

最后time=10

以上思路转换为代码如下:
方法一:

class Solution {
public:
    int leastInterval(vector<char>& tasks, int n) {
        vector<int>count(26,0);
        int maxcnt=0;
        for(auto c:tasks)
            ++count[c-'A'];
        sort(count.begin(),count.end());
        int i=0,time=0;
        while(count.back()>0)
        {
            while(i<=n)
        {
            if(count.back()==0)break;
            if(i<26&&count[25-i]>0)
            {
                --count[25-i];
            }
             ++time;
             ++i;    
        }
           i=0;
           sort(count.begin(),count.end());
        }
        return time;
    }
};

方法一是每一轮完成后进行依次排序,其实也可以用优先级队列来实现,具体思路与上一种方法并没有太大差异;
方法二

class Solution {
public:
    int leastInterval(vector<char>& tasks, int n) {
       vector<int>count(26,0);
        for(auto c:tasks)
            ++count[c-'A'];
        priority_queue<int>pr;
        for(auto c:count)
            if(c>0)pr.push(c);
        int i=0,time=0;
        while(!pr.empty())
        {
           vector<int>temp;
            i=0;
           while(i<=n)
           {
               if(!pr.empty())
               { 
                  if(pr.top()>1)   
                  temp.push_back(pr.top()-1);
                  pr.pop();
             
               }
               ++i;
               ++time;
               if(pr.empty()&&temp.size()==0)break;
           }
            for(auto c:temp)
                   pr.push(c);
        }
        return time; 
    }
};

方法三:仔细分析整个过程发现,完成任务的时间取决与出现次数最多的那个任务

例如:AAABBC n=2
A出现次数最多,我可以直接安排好A为 AxxAxxA, 中间的x可以表示执行其他任务或者等待,直接计算完成任务时间为(3-1)*(2+1)+1

在例如AAABBBCC n=2
这时候A和B出现次数都是最大,安排为AxxAxxAB,完成任务时间为(3-1)(2+1)+2
那么我们可以总结出一个公式:time=(maxcnt-1)
(n+1)+cnt,其中maxcnt表示任务出现最多的次数,n表示冷却时间,cnt表示出现了maxcnt次的任务有多少个
最后有特例,比如当n=0时按公式计算结果小于tasks数组长度,这时候直接取数组长度即可

代码如下:

class Solution {
public:
    int leastInterval(vector<char>& tasks, int n) {
        vector<int>count(26,0);
        int maxcnt=0;
        for(auto c:tasks)
            ++count[c-'A'];
        sort(count.begin(),count.end());
        for(auto c:count)
            if(c==count.back())++maxcnt;
        int res=(count.back()-1)*(n+1)+maxcnt>tasks.size()?(count.back()-1)*(n+1)+maxcnt:tasks.size();
        return res;
    }
};

你可能感兴趣的:(LeetCode,算法)