题目源自于leetcode。好题。普通方法很好想,高效方法想半天。
题目:有一个数组,元素只有0,1,2这三种,现在要将其排序。0全放前面,2全放后面,1放中间。
要求:只遍历一趟。空间复杂度为O(1)。
思路:
换个角度,海阔天空。起初我一直想用左右端指针做,把左端的非0换成0,把右端的非2换成2。但是到中间部位就乱了,因为左右端是同时进行的。
看了网上的解答。方法非常精妙。还是有左右两端指针。但是多一个指针从左到右扫描。其实这个指针既充当扫描指针、又充当中间数字1序列的末尾。扫描的同时实时更新右端指针的0序列和左端指针的2序列。非常的巧妙。
这实际上是快速排序的三路划分思想。下标left表示左路与中路的界限,下标right表示右路和中路的界限。
class Solution {
public:
void sortColors(int A[], int n) {
if(A == NULL || n <= 1)
return;
int left, right, cur;
left = 0; //指向1序列最左侧的1
right = n-1; //指向2序列最左侧的1的左侧的未知元素
cur = 0; //对未知元素进行遍历
while(cur <= right) //cur负责从左到右的遍历
{
if(A[cur] == 0)
{
swap(A[cur++], A[left++]); //A[cur]与1序列最左侧的1交换
}
else if(A[cur] == 1)
{
cur++; //啥也不干
}
else
{
swap(A[cur], A[right--]); //交换过去的那个数还未判定,不要自增
}
}
}
};