力扣621——任務調度器

這道題主要是找規律,優化的時候可以採用貪心算法的思想。

原題

給定一個用字符數組表示的 CPU 需要執行的任務列表。其中包含使用大寫的 A - Z 字母表示的26 種不同種類的任務。任務可以以任意順序執行,並且每個任務都可以在 1 個單位時間內執行完。CPU 在任何一個單位時間內都可以執行一個任務,或者在待命狀態。

然而,兩個相同種類的任務之間必須有長度爲 n 的冷卻時間,因此至少有連續 n 個單位時間內 CPU 在執行不同的任務,或者在待命狀態。

你需要計算完成所有任務所需要的最短時間

示例 1:

輸入: tasks = ["A","A","A","B","B","B"], n = 2
輸出: 8
執行順序: A -> B -> (待命) -> A -> B -> (待命) -> A -> B.

注:

  1. 任務的總個數爲 [1, 10000]。
  2. n 的取值範圍爲 [0, 100]。

原題url:https://leetcode-cn.com/problems/task-scheduler/

解題

找規律

這道題的思路,正向推導的話,其實就是優先排出現次數多的任務,根據間隔 n ,填充任務,直到所有任務的次數最終都減爲0。

因此,我們可以用數組存儲任務的總次數(因爲用大寫英文字母表示任務,那就代表最多隻能有26種任務),排序之後,按照間隔 n ,從大到小取任務,取完後,再對數組排序,重複上述取任務的過程,直到數組的最大值爲0。

接下來我們看看代碼:

public class Solution {
    public int leastInterval(char[] tasks, int n) {
        // 將task放入數組中
        int[] countArray = new int[26];
        for (char task: tasks) {
            countArray[task - 'A']++;
        }
        // 從小到大,進行排序
        Arrays.sort(countArray);
        // 最終耗時
        int time = 0;
        // 從大到小開始遍歷
        while (countArray[25] > 0) {
            // 每次遍歷前n個數
            int i = 0;
            while (i <= n) {
                // 說明所有任務已經執行完成
                if (countArray[25] == 0) {
                    break;
                }
                // 遍歷
                if (i < 26 && countArray[25 - i] > 0) {
                    countArray[25 - i]--;
                }
                // 耗時+1
                time++;
                // 更換任務
                i++;
            }
            // 從小到大排序
            Arrays.sort(countArray);
        }
        return time;
    }
}

提交OK,但執行時間上確實不太好,只打敗了47.62%的 java 執行時間,其時間複雜度爲O(time), time 代表最終的執行時間。

貪心算法

我們再來想想這道題,影響最終執行時間的,有兩個因素,一個是任務中出現的最大次數,另一個就是間隔 n 了。

如果我們站在最多任務的角度,來看這個問題,假設其最大次數爲 maxCount,那麼該任務所需的最短執行時間爲(maxCount - 1) * (n + 1) + 1,如果還有其他 i 個和 maxCount 相同次數的任務,那麼需要在最終的結果上再加上 i。

那麼上面求出來的就是正確答案了嗎?

並不是,因爲上面的最短時間,是當剩餘時間片能夠塞滿任務數小於 maxCount 的所有任務。假設 n 很小,那麼剩餘任務肯定需要在任務數等於 maxCount 的那些任務執行完之後,還要繼續執行。

但因爲最大任務已經可以滿足在間隔時間內執行完,那麼出現次數小於 maxCount 的任務,肯定可以連續執行完成的,也就是不需要空閒等待時間。那麼此時的最短執行時間也就是總任務數了。

接下來我們看看代碼:

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

        // 將task放入數組中
        int[] countArray = new int[26];
        for (char task : tasks) {
            countArray[task - 'A']++;
        }
        // 從小到大,進行排序
        Arrays.sort(countArray);
        // 獲取最大次數
        int maxCount = countArray[25];
        // 如果其他次數都比maxCount小的話,求出針對maxCount的最短時間
        int result = (maxCount - 1) * (n + 1);
        // 遍歷countArray
        for (int i = 25; i >= 0; i--) {
            // 如果有和maxCount相同的,則執行時間+1
            if (countArray[i] == maxCount) {
                result++;
            }
            // 否則,直接結束
            else {
                break;
            }
        }
        
        // 如果總任務數比理論上的最短時間長,說明任務很多,但可以把每個桶填滿,因此最短時間也就是總任務數
        return Math.max(result, tasks.length);
    }
}

提交OK ,在所有 Java 提交中擊敗了100.00%的用戶,確實快了很多。其時間複雜度爲O(M),M 代表總任務數。

總結


以上就是這道題目我的解答過程了,不知道大家是否理解了。這道題主要是找規律,優化的時候可以採用貪心算法的思想。

有興趣的話可以訪問我的博客或者關注我的公衆號、頭條號,說不定會有意外的驚喜。

https://death00.github.io/

公衆號:健程之道

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章