题目
给定一个包含红色、白色和蓝色,一共 n
个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0
、 1
和 2
分别表示红色、白色和蓝色。
示例:
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
函数原型
C
的函数原型:
void sortColors(int* nums, int numsSize){}
边界判断
void sortColors(int* nums, int numsSize)
{
if( nums == NULL || numsSize == 0 )
return;
}
算法设计:快速排序
思想:先完成再优化,快排即可。
int cmp(const void *a,const void *b)
{
return *(int *)a - *(int *)b;
}
void sortColors(int* nums, int numsSize)
{
if( nums == NULL || numsSize == 0 )
return;
qsort(nums, numsSize, sizeof(int),cmp);
}
- 时间复杂度: Θ ( n ∗ l o g n ) \Theta(n*logn) Θ(n∗logn)
- 空间复杂度:
Θ
(
n
)
\Theta(n)
Θ(n)
算法设计:计数排序
思路:使用计数排序的两趟扫描算法。
- 迭代计算出
0
、1
和2
元素的个数,而后按照0
、1
、2
的排序 - 重写当前数组
void sortColors(int* nums, int numsSize)
{
if( nums == NULL || numsSize == 0 )
return;
int red=0, white=0, blue=0, i;
for(i=0; i<numsSize; i++)
switch(nums[i]){
case 0: red++; break;
case 1: white++; break;
case 2: blue++;
}
for(i=0; i<red; i++) nums[i]=0;
for(i=red; i<red+white; i++) nums[i]=1;
for(i=red+white; i<numsSize; i++) nums[i]=2;
}
- 时间复杂度: Θ ( n ) \Theta(n) Θ(n)
- 空间复杂度: Θ ( 1 ) \Theta(1) Θ(1)
算法设计:特征是三路分割,解法是使用三指针进行排序,根据当前指针所指的值进行交换
计数排序遍历了俩次,其实可用一次搞定。
思路:参考了快速排序的中位数思想,快速排序首先要确定一个待分割的元素做中间点 x x x,然后把所有小于等于 x x x 的元素放到 x x x 的左边,大于 x x x 的元素放到其右边。
目标是这样:
假设初始是这样:
定义三个指针:zero
、i
、two
- 所有在子区间 [ 0 , z e r o ) [0, zero) [0,zero) 的元素都等于 0 0 0;
- 所有在子区间 [ z e r o , i ) [zero, i) [zero,i) 的元素都等于 1 1 1;
- 所有在子区间 [ t w o , l e n − 1 ] [two, len - 1] [two,len−1] 的元素都等于 2 2 2。
当遍历到某一元素 e
时:
e
有三种情况:
-
e
=
1
e = 1
e=1
i++
即可,把 1 1 1 纳入到 [ z e r o , i ) [zero, i) [zero,i)
- e = 2 e = 2 e=2
取出 two
前一个元素(暂时这个元素不知道是什么),与 2
交换即可。
而后 two--
,把
2
2
2 纳入到
[
t
w
o
,
l
e
n
−
1
]
[two, len - 1]
[two,len−1]
-
e
=
0
e = 0
e=0
要找到 zero+1
这个元素,一定是
1
1
1
而后交换 zero+1
和 i
而后 zero++
,把
0
0
0 纳入到
[
0
,
z
e
r
o
)
[0, zero)
[0,zero),
相应的 i++
,看下一个元素:
不停的循环…就会排好序。
完整代码:
void swap(int * a, int * b){
int tmp = *a;
*a = *b;
*b = tmp;
}
void sortColors(int* nums, int numsSize){
/* 三指针 一趟扫描 类似三路快排的partition */
int * left = nums;
int * cur = nums;
int * right = nums + numsSize - 1;
while(cur <= right){
if(*cur == 0){
swap(left, cur);
cur ++;
left ++;
}else if(*cur == 1){
cur ++;
}else{
swap(cur, right);
right --;
}
}
return nums;
}
- 时间复杂度: Θ ( n ) \Theta(n) Θ(n)
- 空间复杂度: Θ ( 1 ) \Theta(1) Θ(1)