給定包含 0、1、2 的數組,原地排序使相同顏色相鄰,順序為 0、1、2。不得使用庫排序函數。
進階:能否一次遍歷、常數空間完成?
第一遍統計 0、1、2 的個數 cnt[3]。第二遍按順序覆寫數組:先寫 cnt[0] 個 0,再 cnt[1] 個 1,最後 cnt[2] 個 2。雖然兩遍,但代碼簡單,且只掃描數組兩次,符合「一次遍歷」的廣義理解(不交換元素)。
class Solution {
public:
void sortColors(vector<int>& nums) {
int cnt[3] = {0};
for (int x : nums) ++cnt[x];
int idx = 0;
for (int c = 0; c < 3; ++c)
for (int i = 0; i < cnt[c]; ++i)
nums[idx++] = c;
}
};
維護三個指針:zero 指向下一個 0 的位置,two 指向下一個 2 的位置,i 遍歷。
- nums[i]==0:交換 nums[i++] 和 nums[zero++]
- nums[i]==2:交換 nums[i] 和 nums[two--](i 不動,需重新檢查換來的值)
- nums[i]==1:i++
void sortColors(vector<int>& nums) {
int zero = 0, two = nums.size() - 1, i = 0;
while (i <= two) {
if (nums[i] == 0) swap(nums[i++], nums[zero++]);
else if (nums[i] == 2) swap(nums[i], nums[two--]);
else ++i;
}
}
本題為荷蘭國旗問題經典變體,三向切分是標準最優解。