題目描述:給定一個包含紅色、白色和藍色,一共 n 個元素的數組,原地對它們進行排序,使得相同顏色的元素相鄰,並按照紅色、白色、藍色順序排列。
此題中,我們使用整數 0、 1 和 2 分別表示紅色、白色和藍色。
注意:
不能使用代碼庫中的排序函數來解決這道題。
示例:
輸入: [2,0,2,1,1,0]
輸出: [0,0,1,1,2,2]
進階:
- 一個直觀的解決方案是使用計數排序的兩趟掃描算法。
首先,迭代計算出0、1 和 2 元素的個數,然後按照0、1、2的排序,重寫當前數組。 - 你能想出一個僅使用常數空間的一趟掃描算法嗎?
方法一:
計數排序(給定範圍的計數排序)
class Solution {
public void sortColors(int[] nums) {
DistributionCountingSort(nums,0,2);
}
void DistributionCountingSort(int a[],int l,int u)
{
int n=a.length;
int [] D=new int [u-l+1];
int [] s=new int [n];
int i,j;
for(j=0;j<=u-l;j++)
D[j]=0; //初始化頻率數組
for(i=0;i<=n-1;i++) //計算頻率值
D[a[i]-l]=D[a[i]-l]+1;
for(j=1;j<=u-l;j++) //重用於分佈
D[j]=D[j-1]+D[j];
for(i=n-1;i>=0;i--)
{
j=a[i]-l;
s[D[j]-1]=a[i];
D[j]=D[j]-1;
}
System.arraycopy(s, 0, a, 0, s.length);
}
}
時間效率很高,空間效率比較低。
方法二:
利用劃分的思想,實現三路快速排序
算法
-
初始化0的最右邊界:p0 = 0。在整個算法執行過程中 nums[id < p0] = 0.
-
初始化2的最左邊界 :p2 = n - 1。在整個算法執行過程中 nums[id > p2] = 2.
-
初始化當前考慮的元素序號 :curr = 0.
-
While curr <= p2 :
//這裏只可以是小於等於,因爲根據初始化2的最左邊界定義,如果只是小於數組中p2的數組元素並沒有被考慮 -
若 nums[curr] = 0 :交換第 curr個 和 第p0個 元素,並將指針都向右移。
-
若 nums[curr] = 2 :交換第 curr個和第 p2個元素,並將 p2指針左移 。
-
若 nums[curr] = 1 :將指針curr右移。
class Solution {
public void sortColors(int[] nums) {
int n=nums.length;
int p0=0;
int p1=n-1;
int cur=0;
while(cur<=p1)
{
if(nums[cur]==0)
{
swap(nums,p0,cur);
p0++;
cur++;
}
else if(nums[cur]==2)
{
swap(nums,p1,cur);
p1--;
}
else
cur++;
}
}
void swap(int [] nums,int a,int b)
{
int temp=nums[a];
nums[a]=nums[b];
nums[b]=temp;
}
}