LeetCode | Sort Colors(荷兰国旗问题)


Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue.

Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.

Note:
You are not suppose to use the library’s sort function for this problem.

Follow up:
A rather straight forward solution is a two-pass algorithm using counting sort.
First, iterate the array counting number of 0’s, 1’s, and 2’s, then overwrite array with total number of 0’s, then 1’s and followed by 2’s.

Could you come up with an one-pass algorithm using only constant space?

题目解析:

在提示当中已经提到了通过对0,1,2分别计数,然后对整个数组重新赋值,可以达到想要的结果。方法很巧妙。但如果元素只是记录的关键字的话,这样做就不合适了。还是寻求更通用的排序方法比较好。


方案一:

这道题目也就三种数,我们可以用快排的partition的i,j都向后移的方法来进行,第一次以0为关键字, 凡是为0都挪到i位置,不是0的都挪到后面。对剩余的部分再进行一次partition。这样进行两趟partition就能解决问题。

通过这道题又发现了新的观点。partition的“i,j都向后移”方法中key是可以任意指定一个数据的,而不一定非要是数组中的元素,也不一定非要是数组的起始位置的元素。而partition的“前后指针”方法,是需要某一个元素变成起始位置的元素后再进行排序。

代码如下:

class Solution {
public:
    void sortColors(int A[], int n) {
        int mid = Partition(A,0,n-1,0);
        Partition(A,mid,n-1,1);
    }

    int Partition(int A[],int begin,int end,int key){
        int i,j;

        for(i = j = begin;j <= end;j++){
            if(A[j] == key){
                Swap(&A[i],&A[j]);
                i++;
            }
        }
        return i;
    }

    void Swap(int *a,int *b){
        int temp = *a;
        *a = *b;
        *b = temp;
    }
};

方案二:

可以利用三个指针的方法来求解。当i,j,k。k指向最后。

1、当j为1的时候,就j++,不进行交换

2、当j为0的时候,就和i处的元素交换,然后i++和j++。(这里的j++是因为保证了j前面的元素要么为0,要么为1,如果加强条件i==j时不交换,更省一点点时间

3、当j为2的时候,就和k处的元素交换,然后k–,但j不变,重新判断j处的新值(也可以判断k处的值再交换,不过增添了麻烦,直接交换比较好)


class Solution{
public:
    void sortColors(int A[],int n){
        int i,j,k;
        i = j = 0;
        k = n-1;

        while(j<=k){
            if(A[j] == 0){
                if(i != j)
                    Swap(&A[i],&A[j]);
                i++;
                j++;
            }else if(A[j] == 1) //该加else就必须加,不能单独形成else,不然这句j+1后,下句判断就以新的j来判断了
                j++;
            else{
                Swap(&A[j],&A[k]);
                k--;
            }
        }
    }

    void Swap(int *a,int *b){
        int temp = *a;
        *a = *b;
        *b = temp;
    }
};

点赞