領釦網演算法學習筆記 - 75
阿新 • • 發佈:2018-11-24
領釦網演算法學習筆記
本系列的演算法題目來自領釦網
陣列類演算法第五天
題目:顏色分類
給定一個包含紅色、白色和藍色,一共 *n *個元素的陣列,原地對它們進行排序,使得相同顏色的元素相鄰,並按照紅色、白色、藍色順序排列。
此題中,我們使用整數 0、 1 和 2 分別表示紅色、白色和藍色。
示例:
輸入: [2,0,2,1,1,0]
輸出: [0,0,1,1,2,2]
說明:
- 進階:
- 一個直觀的解決方案是使用計數排序的兩趟掃描演算法。
首先,迭代計算出0、1 和 2 元素的個數,然後按照0、1、2的排序,重寫當前陣列。 - 你能想出一個僅使用常數空間的一趟掃描演算法嗎?
- 一個直觀的解決方案是使用計數排序的兩趟掃描演算法。
解題過程:
思路:
看到這題的第一個想法就是說明中的方案:我把個數記下來就好了,管你順序是啥,看到進階後放棄了這種做法,然後想法是:定義兩個變數用來記錄紅色和藍色的位置,然後遇到紅色往前插入,其餘球往後移一個,遇到藍色,則往後插入,其餘球往前移動一個,但是這樣做的話,移動球的代價太大,直接否決,
然後我想的是:我不移動球,因為顏色已經確定,順序頁已經確定,我交換位置,
- 定義兩個變數分別記錄紅藍的位置,初始值:紅球為0,籃球為陣列的長度,位與最後。
- 當判斷到一個藍球時,與記錄籃球的位置交換,然後籃球位置往前移一位,同時因為互換了球,所以交換的位置需要重新判斷,
- 當判斷是白球時,白球位置加一,然後繼續判斷,原因是紅球往前,藍球往後,白球放中間,位置不用變。
- 當判斷是紅球時,將紅球位置程式設計紅球,此時如果不存在白球,那麼對白球無影響,那麼紅球與白球的位置相同,兩者位置都往後移一個,如果存在白球,則紅球位置將移到白球上,需要補一個給白球,此時補得位置剛好是判斷位置,所以直接將判斷位置變成白色即可。
程式碼如下:
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,然後直接再判斷交換過來的是紅白色,但是效率如何,未知。感覺速度不會提升。
其實解決問題的方法很多,找到最好的就需要好好思考了。