[LeetCode][M0621]任务调度器(Java)(贪心)

题目描述

给你一个用字符数组 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)
链接:https://leetcode-cn.com/problems/task-scheduler
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

看到这几个示例,最先想到的就是数学中求组合数的插入法

要满足所有相同字符都间隔 n 位,那么只需要排列最多的字符就好了

拿示例三举例:tasks = [“A”,“A”,“A”,“A”,“A”,“A”,“B”,“C”,“D”,“E”,“F”,“G”], n = 2

先排列 字符个数最多的 “A”

A -> () -> () -> A -> () -> () -> A -> () -> () -> A -> () -> () -> A -> () -> () -> A

然后在 A 的后边插入第二长的字符 B (其实剩下一样长了,顺序取而已)

A -> B -> () -> A -> () -> () -> A -> () -> () -> A -> () -> () -> A -> () -> () -> A

以此类推,其他字符会填满这些空档。

结束了?没,假如其他的字符总个数超过了这些空档的个数,怎么办?

可以在拓展一下,如果继续按这种方式,往后边拓展 A 呢?

举例 :tasks = [“A”,“A”,“A”,“B”,“B”,“C”,“C”,“D”,“E”,“F”,“G”], n = 2

A -> () -> () -> A -> () -> () -> A

A -> B -> () -> A -> () -> () -> A -> () -> () -> B

A -> B -> () -> A -> C -> () -> A -> C -> () -> B

A -> B -> D -> A -> C -> () -> A -> C -> () -> B

A -> B -> D -> A -> C -> E -> A -> C -> F -> B -> G

这样顺序下来就好了,不用担心添加的 B 和插入的 B 会间隔不够,因为 A 是个数最多的,B 再多也只能和 A 一样长,也就是说 B 填充下来,永远不会到 最后一个 A 后边。

这种情况,需要的时间就是和长度一样长。

还有一种情况需要注意,那就是出现几个等长,怎么办?

其实很简单,A B C 个数相同且最大,那么只需要在A后边再加上B C就好了。

反思错误

Java代码

class Solution {
    public int leastInterval(char[] tasks, int n) {
        // 字符数组 总长度
        int len = tasks.length;
        // 如果间隔是0,那么直接返回总长度
        if(n == 0) return len;
        // 映射字符个数
        int[] taskc = new int[26];
        // 最大个数
        int max = 0;
        // cnt 最大个数的字符有几种;idx 计算字符对应的脚标
        int cnt = 0, idx = 0;
        for(int i=0;i<len;++i) {
            // 每次都计算tasks[i]-'A',感觉浪费时间,所以加了一个idx
            idx = tasks[i]-'A';
            taskc[idx]++;
            max = max > taskc[idx] ? max : taskc[idx];
        }
        for(int count:taskc) {
            cnt += count==max ? 1 : 0;
        }
        int maxlen = (max-1) * (n+1) + cnt;
        return maxlen > len ? maxlen : len;
    }
}

执行结果

执行用时:2 ms , 在所有 Java 提交中击败了 94.43% 的用户
内存消耗: 40 MB , 在所有 Java 提交中击败了 9.60% 的用户
通过测试用例:71 / 71

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值