【Sort】75. 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?

当然可以像这样一下就AC。。。。

class Solution {
public:
    void sortColors(vector<int>& nums) {
        sort(nums.begin(),nums.end());
    }
};

但是这个题想考什么呢。。。这里提到了counting sort(计数排序)

这是一种非比较排序算法,适用于待排序的数范围不大并且有很多重复的情况。算法思想很简单:如果知道了一堆数中有多少个数比a大,也就知道了a的位置(a是某个元素)。但是怎么通过非比较的方式去统计有多少个数比a大呢?答案是通过和数组下标建立映射关系。

假如有一堆数:0,0,0,1,1,2,2,2,2存在A数组里,现在考虑C数组:

C[0]、C[1]、C[2]、C[3]、C[4]、C[5]、C[6]、C[7]、C[8]、C[9]

初始化它们为0。然后我们遍历A,用C[A[i]]+=1来统计A[i]出现的次数(注意这里把待排序的A[i]转换成了C的下标),得到:

C[0]、C[1]、C[2]、C[3]、C[4]、C[5]、C[6]、C[7]、C[8]、C[9]

3、2、4、0、0、0、0、0、0

这个过程也反映了统计排序的一个劣势:如果待排序的数范围很大,那么空间的开销将非常大!

现在我们遍历C,做C[i]+=C[i-1],这就得到了有多少个小于等于A[i]的数的个数。

最后我们用一个数组B来保存结果,遍历A,做:B[C[A[j]]]=A[j]; C[A[j]]--;也就是找到A[j]合适的位置,把A[j]放进去,同时减小负责计数的C。这里虽然看上去复杂,但其实意思非常清晰:A[j]表示这个待排序的数,也是C的下标,C[A[j]]表示A[j]前面有多少个数小于等于它,那么C[A[j]]就是A[j]在B中的新位置(因为是小于等于,它自己也被包括了,所以位置是C[A[j]])。

以上就是计数排序的思路。

所以这个题就这样解决啦:

class Solution {
public:
    void sortColors(vector<int>& nums) {
        vector<int> counter(3,0);
        vector<int> res(nums.size(),0);
        for(int i=0;i<nums.size();i++)
            counter[nums[i]]++;//count the number of 0s,1s and 2s
        for(int i=1;i<counter.size();i++)
            counter[i]+=counter[i-1];//now counter[i]=the number of elements greater than or equal to nums[i]
        for(int i=nums.size()-1;i>=0;i--){
            res[counter[nums[i]]-1]=nums[i];
            counter[nums[i]]--;
        }
        nums=res;
    }
};
需要注意。。。上面的过程参考了《算法导论》,A的下标是从1开始的,但实际编程下标都是从0开始,所以

res[counter[nums[i]]-1]=nums[i];
这里要减1。
这个题的follow-up很有意思:

如何one-pass解决掉它?

class Solution {
public:
    void sortColors(vector<int>& nums) {
        int j=0,k=nums.size()-1;
        for(int i=0;i<=k;i++){
            if(nums[i]==0)
                swap(nums[i],nums[j++]);
            else if(nums[i]==2)
                swap(nums[i--],nums[k--]);
        }
    }
};
这其实就是大名鼎鼎的荷兰国旗问题了(Dutch Nation Flag Problem),可以参考: https://en.wikipedia.org/wiki/Dutch_national_flag_problem

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
荷兰国旗问题是一个经典的排序问题,它要求按照荷兰国旗的颜色顺序(红、白、蓝)对一个包含红、白、蓝三种颜色的数组进行排序。 快速排序算法可以用来解决荷兰国旗问题。该算法基于分治的思想,通过多次划分和交换元素来达到排序的目的。以下是快速排序算法解决荷兰国旗问题的步骤: 1. 选择一个枢轴元素(一般是数组的最后一个元素)。 2. 初始化三个指针:low指向数组的起始位置,high指向数组的末尾位置,mid指向数组的起始位置。 3. 从头遍历数组,如果当前元素小于枢轴元素,则交换当前元素和mid指针指向的元素,并将mid指针后移一位。 4. 如果当前元素等于枢轴元素,则将high指针前移一位。 5. 如果当前元素大于枢轴元素,则交换当前元素和high指针指向的元素,并将high指针前移一位。 6. 重复步骤3到步骤5,直到low指针和high指针相遇为止。 7. 最后,将枢轴元素放在mid指针的位置上,这样数组就被分成了三个部分:小于枢轴元素的部分、等于枢轴元素的部分和大于枢轴元素的部分。 8. 递归地对小于和大于枢轴元素的部分进行排序。 以下是一个示例荷兰国旗问题的快速排序的实现(使用Python语言): ```python def dutch_flag_sort(arr): def swap(arr, i, j): arr[i], arr[j] = arr[j], arr[i] def quicksort(arr, low, high): if low < high: pivot = arr[high] mid = low for i in range(low, high): if arr[i] < pivot: swap(arr, i, mid) mid += 1 swap(arr, mid, high) quicksort(arr, low, mid - 1) quicksort(arr, mid + 1, high) quicksort(arr, 0, len(arr) - 1) return arr # 示例用法 arr = [2, 0, 2, 1, 1, 0] sorted_arr = dutch_flag_sort(arr) print(sorted_arr) ``` 上述示例代码会输出 `[0, 0, 1, 1, 2, 2]`,即按照荷兰国旗顺序排序的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值