给定一个用字符数组表示的 CPU 需要执行的任务列表。其中包含使用大写的 A - Z 字母表示的26 种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。CPU 在任何一个单位时间内都可以执行一个任务,或者在待命状态。
然而,两个相同种类的任务之间必须有长度为 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。
你需要计算完成所有任务所需要的最短时间。
解答
方法一:
使用最大值堆,保存剩余不同类型的任务数量,在堆不为空的情况下,处理堆中的任务。由于间隔n,因此每轮处理n+1次。
①每次,若堆不空,堆顶元素>1,则将该元素-1放入临时list,并删除该堆顶元素
堆顶元素<=1,则删除该堆顶元素
②轮数i++,时间++
③重新将临时list中的元素加入queue
④如果queue为空,并且临时list为空,直接返回times,否则,继续循环处理queue
public int leastInterval(char[] tasks, int n) { int times = 0; int[] count = new int[26]; for (char ch : tasks) { count[ch - 'A']++; } PriorityQueue<Integer> queue = new PriorityQueue<Integer>(26, Collections.reverseOrder()); // 最大值堆 for (int value : count) { if (value > 0) { queue.add(value); } } while(!queue.isEmpty()) { List<Integer> tempList = new ArrayList<Integer>(); // 临时list,存储处理过的任务 // 由于间隔是n,所以每一轮处理n+1种任务,任务种类数没有n+1就放空 int i = 0; while(i <= n) { if (!queue.isEmpty()) { if (queue.peek() > 1) { tempList.add(queue.poll() - 1); } else { queue.poll(); } } i++; times++; if (tempList.size() == 0 && queue.isEmpty()) { return times; } } for (int value : tempList) { queue.add(value); } } return times; }
方法二:
找规律取巧
public int leastInterval(char[] tasks, int n) { int times = 0; int[] count = new int[26]; for (char ch : tasks) { count[ch - 'A']++; } int max = 0; // 出现最多次的任务次数 for (int value : count) { if (value > max) { max = value; } } int countForMax = 0; // 出现最多次的任务种类 for (int value : count) { if (value == max) { countForMax ++; } } // (max - 1)处理的轮数,-1是因为多出来这个任务之后不会有间隔,后面再统计 // (n + 1)表示每轮处理需要的时间 // 任务的任务countForMax直接加上即可,因为这些任务之后不需要加放空的时间 times = (max - 1) * (n + 1) + countForMax; return times < tasks.length ? tasks.length : times; }