设计类算法题 - 即合理利用数据结构, 得到算法

444 阅读1分钟

任务调度器

题目

image.png

版本1 正确

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

        // 任务种类 -> 剩余执行次数的映射
        Map<Character, Integer> task2NumMap = new HashMap<>();
        // 任务种类 -> 冷却时间的映射
        Map<Character, Integer> task2TimeMap = new HashMap<>();

        // 维护一个冷却时间为0的大顶堆
        PriorityQueue<Character> priorityQueue = new PriorityQueue<>(new Comparator<Character>() {
            @Override
            public int compare(Character o1, Character o2) {
                return task2NumMap.get(o2) - task2NumMap.get(o1);
            }
        });
        int allTaskNum = 0;
        for (char task : tasks) {
            allTaskNum ++;
            task2NumMap.put(task, task2NumMap.getOrDefault(task, 0) + 1);
            task2TimeMap.putIfAbsent(task, 0);
        }

        // 一定要在所有次数都统计完毕后, 才构造优先队列, 才能正确的排序
        task2NumMap.forEach((k, v) -> {
            priorityQueue.offer(k);
        });

        // 每次选择任务依据几个准则
        // (1) 如果都在冷却, 没得选, 等待一个cpu时间
        // (2) 如果只有一个冷却好了的, 直接选
        // (3) 如果有多个冷却好的任务, 选择剩余执行次数最大的那个
        int ans = 0;
        while (allTaskNum > 0) {
            if (priorityQueue.size() == 0) {
                // 等待一个cpu时间 没有执行任何任务
                ans ++;
            } else {
                // 大顶堆顶部的元素就是应该执行的任务
                Character executeTask = priorityQueue.poll();
                allTaskNum --;
                ans ++;
                // 调整task2NumMap
                int surplusNum = task2NumMap.get(executeTask) - 1;
                task2NumMap.put(executeTask, surplusNum);

                // 调整task2TimeMap, 这里调整为n + 1, 因为下面会统一减1
                task2TimeMap.put(executeTask, n + 1);

            }

            // 每等待一个cpu时间, 或者说执行了某个任务后
            // task2TimeMap中所有非0的值都应该减去1, 如果有减去到0的, 需要添加到priorityQueue中
            task2TimeMap.forEach((k, time) -> {
                // 注意冷却时间如果归零, 同时还要满足依旧有需要执行的次数, 才需要添加到优先队列中
                if (time - 1 == 0 && task2NumMap.get(k) > 0) {
                    priorityQueue.offer(k);
                }

                if (time > 0) {
                    task2TimeMap.put(k, time - 1);
                }

            });
        }

        return ans;
    }
   

正确的原因

(1) 注意优先队列赋值的情况, 需要等统计次数的map遍历完, 再进行赋值, 才能得到正确的排序

(2) 执行的过程中, 往优先队列添加值, 需要考虑是否有剩余次数了, 再添加