题目描述
给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。在任何一个单位时间,CPU 可以完成一个任务,或者处于待命状态。
然而,两个 相同种类 的任务之间必须有长度为整数 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。
你需要计算完成所有任务所需要的 最短时间 。
解法
其实就是贪心算法,每次选择当前能选择的任务中个数最多的那种任务执行。但是我用优先队列做有一个用例过不了。另外优先队列想要每次peek都是优先级最大的值的话,它的Comparator必须是((a,b)->(b.priority - a.priority))。但其实这种做法还是稍微有点复杂。看了评论区有大佬做的很简单,是直接用数学公式计算的,https://leetcode-cn.com/problems/task-scheduler/solution/jian-ming-yi-dong-de-javajie-da-by-lan-s-jfl9/。
class Solution {
/**
* 621.任务调度器
*
* @param tasks 任务列表
* @param n 同种任务之间的执行间隔
* @return 执行完所有任务需要的最短时间
*/
public int leastInterval(char[] tasks, int n) {
int interval = n;
//当前可执行的任务队列
PriorityQueue<Task> execuable = new PriorityQueue<>();//某种任务剩余得越多优先级越高
Set<Character> allTasks = new HashSet<>();
Map<Character, Task> map = new HashMap<>();
initExecuable(tasks, allTasks, execuable, map);
int res = 0;
while (!allTasks.isEmpty()) {
res++;
if (!execuable.isEmpty()) {
Task tmp = execuable.peek();
tmp.cooldown = n+1;//执行后有冷却
execuable.remove(tmp);
tmp.num--;//执行完任务数-1
if (tmp.num == 0) {
allTasks.remove(tmp.task);
}
}
//执行完一个任务之后更新其他种类任务得状态
for (Character a : allTasks) {
Task task = map.get(a);
if (task.cooldown != 0 ) {
task.cooldown--;
if (task.cooldown == 0) {
execuable.add(task);
}
}
}
}
return res;
}
public void initExecuable(char[] tasks, Set<Character> allTasks, PriorityQueue<Task> execuable, Map<Character, Task> map) {
for (char a : tasks) {
if (allTasks.add(a)) {
map.put(a, new Task(a, 1, 0));
execuable.add(map.get(a));
} else {
map.get(a).num++;
}
}
}
class Task implements Comparable{
char task;
public int cooldown;//该种任务的剩余冷却时间冷却
public int num;//该种任务还剩多少个
public Task(char task, int num, int cooldown) {
this.task = task;
this.num = num;
this.cooldown = cooldown;
}
@Override
public int compareTo(Object o) {
if (o instanceof Task) {
return ((Task) o).num - this.num;
} else {
throw new RuntimeException();
}
}
}
}