力扣621——任务调度器

这道题主要是找规律,优化的时候能够采用贪心算法的思想。
<!-- more -->java

原题

给定一个用字符数组表示的 CPU 须要执行的任务列表。其中包含使用大写的 A - Z 字母表示的26 种不一样种类的任务。任务能够以任意顺序执行,而且每一个任务均可以在 1 个单位时间内执行完。CPU 在任何一个单位时间内均可以执行一个任务,或者在待命状态。git

然而,两个相同种类的任务之间必须有长度为 n 的冷却时间,所以至少有连续 n 个单位时间内 CPU 在执行不一样的任务,或者在待命状态。github

你须要计算完成全部任务所须要的最短期算法

示例 1:segmentfault

输入: tasks = ["A","A","A","B","B","B"], n = 2
输出: 8
执行顺序: A -> B -> (待命) -> A -> B -> (待命) -> A -> B.

注:数组

  1. 任务的总个数为 [1, 10000]。
  2. n 的取值范围为 [0, 100]。

原题url:https://leetcode-cn.com/probl...优化

解题

找规律

这道题的思路,正向推导的话,其实就是优先排出现次数多的任务,根据间隔 n ,填充任务,直到全部任务的次数最终都减为0。url

所以,咱们能够用数组存储任务的总次数(由于用大写英文字母表示任务,那就表明最多只能有26种任务),排序以后,按照间隔 n ,从大到小取任务,取完后,再对数组排序,重复上述取任务的过程,直到数组的最大值为0。spa

接下来咱们看看代码:code

public class Solution {
    public int leastInterval(char[] tasks, int n) {
        // 将task放入数组中
        int[] countArray = new int[26];
        for (char task: tasks) {
            countArray[task - 'A']++;
        }
        // 从小到大,进行排序
        Arrays.sort(countArray);
        // 最终耗时
        int time = 0;
        // 从大到小开始遍历
        while (countArray[25] > 0) {
            // 每次遍历前n个数
            int i = 0;
            while (i <= n) {
                // 说明全部任务已经执行完成
                if (countArray[25] == 0) {
                    break;
                }
                // 遍历
                if (i < 26 && countArray[25 - i] > 0) {
                    countArray[25 - i]--;
                }
                // 耗时+1
                time++;
                // 更换任务
                i++;
            }
            // 从小到大排序
            Arrays.sort(countArray);
        }
        return time;
    }
}

提交OK,但执行时间上确实不太好,只战胜了47.62%的 java 执行时间,其时间复杂度为O(time), time 表明最终的执行时间。

贪心算法

咱们再来想一想这道题,影响最终执行时间的,有两个因素,一个是任务中出现的最大次数,另外一个就是间隔 n 了。

若是咱们站在最多任务的角度,来看这个问题,假设其最大次数为 maxCount,那么该任务所需的最短执行时间为(maxCount - 1) * (n + 1) + 1,若是还有其余 i 个和 maxCount 相同次数的任务,那么须要在最终的结果上再加上 i。

那么上面求出来的就是正确答案了吗?

并非,由于上面的最短期,是当剩余时间片可以塞满任务数小于 maxCount 的全部任务。假设 n 很小,那么剩余任务确定须要在任务数等于 maxCount 的那些任务执行完以后,还要继续执行。

但由于最大任务已经能够知足在间隔时间内执行完,那么出现次数小于 maxCount 的任务,确定能够连续执行完成的,也就是不须要空闲等待时间。那么此时的最短执行时间也就是总任务数了。

接下来咱们看看代码:

public class Solution {
    public int leastInterval(char[] tasks, int n) {
        if (tasks.length == 0 || n == 0) {
            return tasks.length;
        }

        // 将task放入数组中
        int[] countArray = new int[26];
        for (char task : tasks) {
            countArray[task - 'A']++;
        }
        // 从小到大,进行排序
        Arrays.sort(countArray);
        // 获取最大次数
        int maxCount = countArray[25];
        // 若是其余次数都比maxCount小的话,求出针对maxCount的最短期
        int result = (maxCount - 1) * (n + 1);
        // 遍历countArray
        for (int i = 25; i >= 0; i--) {
            // 若是有和maxCount相同的,则执行时间+1
            if (countArray[i] == maxCount) {
                result++;
            }
            // 不然,直接结束
            else {
                break;
            }
        }
        
        // 若是总任务数比理论上的最短期长,说明任务不少,但能够把每一个桶填满,所以最短期也就是总任务数
        return Math.max(result, tasks.length);
    }
}

提交OK ,在全部 Java 提交中击败了100.00%的用户,确实快了不少。其时间复杂度为O(M),M 表明总任务数。

总结

以上就是这道题目个人解答过程了,不知道你们是否理解了。这道题主要是找规律,优化的时候能够采用贪心算法的思想。

有兴趣的话能够访问个人博客或者关注个人公众号、头条号,说不定会有意外的惊喜。

https://death00.github.io/

公众号:健程之道

相关文章
相关标签/搜索