1. 程式人生 > >leetcode621 - Task Scheduler - medium

leetcode621 - Task Scheduler - medium

capital med val get amp api 更新 order poll()


Given a char array representing tasks CPU need to do. It contains capital letters A to Z where different letters represent different tasks.Tasks could be done without original order. Each task could be done in one interval. For each interval, CPU could finish one task or just be idle.
However, there is a non-negative cooling interval n that means between two same tasks, there must be at least n intervals that CPU are doing different tasks or just be idle.
You need to return the least number of intervals the CPU will take to finish all the given tasks.
Example 1:
Input: tasks = ["A","A","A","B","B","B"], n = 2
Output: 8
Explanation: A -> B -> idle -> A -> B -> idle -> A -> B.
Note:
1. The number of tasks is in the range [1, 10000].
2. The integer n is in the range [0, 100].

1.max堆。
1.建造一個堆,它按照字符出現的頻率從大到小吐出頻率。
2.統計字符頻率。
3.在堆非空時都進行while循環,內部做一個n+1長度的循環cycle,當然也可能走不完這個cycle。這個cycle的目的是從堆取,把前n+1個最棘手(頻率最高最需要早點安排)的任務排在這個cycle裏。每次取出來後還要把減掉的頻率記一下在temp裏,最後一起放回去。如果heap裏沒數取了說明這一輪cycle放不滿,你接下來要空循環來加idle湊time。如果heap裏沒數取了而且temp裏也沒數取了,說明下一輪肯定沒了,這是最後一輪,從而不用接著空循環加idle湊滿n+1,趕緊break走人吧。

2.數學法。
其實cycle數是由最大頻率決定的。總time基本上= (maxF - 1)* (n + 1) + (f為最大頻率的字符有多少種)。如果出現這個time算出來比總task數還少的情況,那就取task,也就是兩者取其大。但我總覺得這個很難和面試官好好證明這個為什麽是正確的。

細節:
1.用temp數組在最後放回去更新的頻率是避免在一個cycle裏放重復的任務。因為你剛更新了頻率就放回去可能還是最大頻率,接著馬上又被拿出來了。
2.先插最大的比如A,然後插第二大的比如B,這樣下去不用擔心比如B會不會在n時間內撞到。因為最大的是頻率最大,那麽就是有A活的一天才有B,那永遠都有A幫你維持n的距離,不用擔心。
3.maxHeap比較器的優雅寫法(對基礎類型):new PriorityQueue<>(Collections.reverseOrder());
4.比較器內部compare(T a, T b)內部的T的填寫嚴格按照泛型指定的類型,比如對Integer的比較器,你這裏就寫Integer不能寫int。這是Override啊同學。

實現:

class Solution {
    public int leastInterval(char[] tasks, int n) {
        
        // PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>() {
        //     @Override
        //     // P2: int a, int b是錯的,嚴格按照泛型來。
        //     public int compare(Integer a, Integer b) {
        //         return b - a;
        //     }
        // });
        // P1: 自帶數據結構的大跟堆的優雅寫法
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
        
        Map<Character, Integer> map = new HashMap<>();
        for (char c : tasks) {
            map.put(c, map.getOrDefault(c, 0) + 1);
        }
        for (char c : map.keySet()) {
            maxHeap.offer(map.get(c));
        }
        
        int time = 0;
        while (!maxHeap.isEmpty()) {
            List<Integer> temp = new ArrayList<>();
            for (int i = 0; i < n + 1; i++) {
                if (!maxHeap.isEmpty()) {
                    if (maxHeap.peek() > 1) {
                        temp.add(maxHeap.peek() - 1);
                    }
                    maxHeap.poll();
                }
                time++;
                if (maxHeap.isEmpty() && temp.isEmpty()) {
                    break;
                }
            }
            for (int newF : temp) {
                maxHeap.offer(newF);
            }
        }
        return time;
    }
}

leetcode621 - Task Scheduler - medium