1. 程式人生 > >領釦網演算法學習筆記 - 75

領釦網演算法學習筆記 - 75

領釦網演算法學習筆記

本系列的演算法題目來自領釦網

陣列類演算法第五天

題目:顏色分類

給定一個包含紅色、白色和藍色,一共 *n *個元素的陣列,原地對它們進行排序,使得相同顏色的元素相鄰,並按照紅色、白色、藍色順序排列。
此題中,我們使用整數 0、 1 和 2 分別表示紅色、白色和藍色。

示例:

輸入: [2,0,2,1,1,0]
輸出: [0,0,1,1,2,2]

說明:

  1. 進階:
    • 一個直觀的解決方案是使用計數排序的兩趟掃描演算法。
      首先,迭代計算出0、1 和 2 元素的個數,然後按照0、1、2的排序,重寫當前陣列。
    • 你能想出一個僅使用常數空間的一趟掃描演算法嗎?

解題過程:

思路:

看到這題的第一個想法就是說明中的方案:我把個數記下來就好了,管你順序是啥,看到進階後放棄了這種做法,然後想法是:定義兩個變數用來記錄紅色和藍色的位置,然後遇到紅色往前插入,其餘球往後移一個,遇到藍色,則往後插入,其餘球往前移動一個,但是這樣做的話,移動球的代價太大,直接否決,

然後我想的是:我不移動球,因為顏色已經確定,順序頁已經確定,我交換位置,

  1. 定義兩個變數分別記錄紅藍的位置,初始值:紅球為0,籃球為陣列的長度,位與最後。
  2. 當判斷到一個藍球時,與記錄籃球的位置交換,然後籃球位置往前移一位,同時因為互換了球,所以交換的位置需要重新判斷,
  3. 當判斷是白球時,白球位置加一,然後繼續判斷,原因是紅球往前,藍球往後,白球放中間,位置不用變。
  4. 當判斷是紅球時,將紅球位置程式設計紅球,此時如果不存在白球,那麼對白球無影響,那麼紅球與白球的位置相同,兩者位置都往後移一個,如果存在白球,則紅球位置將移到白球上,需要補一個給白球,此時補得位置剛好是判斷位置,所以直接將判斷位置變成白色即可。

程式碼如下:

class Solution {
    public void sortColors(int[] nums) {
        if((nums == null && nums.length == 0
) || nums.length == 1){ return ; } int blueNum = nums.length; // 記錄藍色的位置,同時兼顧迴圈次數的身份 int redNum = 0; // 記錄紅色的位置 for(int i=0;i<blueNum;i++){ // 迴圈陣列 if(nums[i] == 2){ // 判斷是否為藍色 blueNum--; // 記錄的藍色位置-1 nums[i] = nums[blueNum]; // 因為陣列是從0開始,所以這裡-1之後剛好是末尾的值 // 將藍色位置的資料賦給當前位置 nums[blueNum] = 2; // 將藍色位置變成藍色 i--; // 交換後需要重新判斷,所以將判斷的位置退後一個 } // 白色不用管,所以不判斷 else if(nums[i] == 0){ // 判斷是否為紅色 if(redNum != i){ // 判斷是否存在白球,如果存在,則紅色數量不等於當前判斷的數量 // 此時當前判斷的位置等於已知的紅色數量加已知的白球數量 nums[i] = 1; // 存在白球則將當前位置變為白色 } nums[redNum] = 0; // 因為無論存不存在白色,都需要將紅色位置變成紅色 redNum++; // 然後紅色位置往後移一位,所以直接拿出來 } } } } // 用時小於1ms

後續思考+總結:

該題不打算做高質量的分析,感覺這個是最佳的思路了,還有一個就是判斷完是藍色後不使用else,然後直接再判斷交換過來的是紅白色,但是效率如何,未知。感覺速度不會提升。

其實解決問題的方法很多,找到最好的就需要好好思考了。