计数排序

来源:互联网 发布:淘宝抢购秒杀器哪个好 编辑:程序博客网 时间:2024/05/17 04:00

起源:

今天用计数排序解决了几道问题,感觉这个算法很有用,于是仔细研究了下,并且在《算法导论》一书中读到了相关的内容。

计数排序的优势

计数排序的时间复杂度为O(n+ k)..其中要设定一个辅助count数组。统计原数组中,每个元素出现的次数。
直观的感觉是记录<=x元素的个数,那么把x元素放到后面就可以了,那么就将所有的元素都排好序了,但是这种思想还需要一个临时数组存储排好序的数组。

通俗地理解,例如有10个年龄不同的人,统计出有8个人的年龄比A小,那A的年龄就排在第9位,用这个方法可以得到其他每个人的位置,也就排好了序。当然,年龄有重复时需要特殊处理(保证稳定性),这就是为什么最后要反向填充目标数组,以及将每个数字的统计减去1的原因。

算法的步骤如下:
1找出待排序的数组中最大和最小的元素
2统计数组中每个值为i的元素出现的次数,存入数组 C 的第 i 项
//得到小于等于x元素的个数
3对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
//保持稳定性
4 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1.

实践

颜色分类

给定一个包含红,白,蓝且长度为 n 的数组,将数组元素进行分类使相同颜色的元素相邻,并按照红、白、蓝的顺序进行排序。

我们可以使用整数 0,1 和 2 分别代表红,白,蓝。

给你数组 [1, 0, 1, 2], 需要将该数组排序为 [0, 1, 1, 2]。

class Solution {    /**     * @param nums: A list of integer which is 0, 1 or 2      * @return: nothing     */    public void sortColors(int[] nums) {        // write your code here        if (nums == null || nums.length == 0){            return;        }        int[] count = new int[3];        int[] tmp = new int[nums.length];        for (int i = 0; i < nums.length; i++){            count[nums[i]]++;        }        for (int i = 1; i < count.length; i++){            count[i] += count[i - 1];        }        for (int j = nums.length - 1; j >= 0; j--){            tmp[count[nums[j]] - 1] = nums[j];            count[nums[j]]--;        }        for (int i = 0; i < nums.length; i++){            nums[i] = tmp[i];        }    }}

思考一步:

这种解法可以优化的地方在于不一定需要临时数组tmp,因为count数组得下标对应的为nums[i]中的元素,而且数组下标肯定是有序的,所以直接填充就好。

class Solution {    /**     * @param nums: A list of integer which is 0, 1 or 2      * @return: nothing     */    public void sortColors(int[] nums) {        // write your code here        if (nums == null || nums.length == 0){            return;        }        int[] count = new int[3];        int[] tmp = new int[nums.length];        for (int i = 0; i < nums.length; i++){            count[nums[i]]++;        }        int index = 0;        for (int j = 0; j < count.length; j++){            while (count[j]-- > 0){                nums[index++] = j;            }        }    }}

注意这里我定义了全局索引index,用来扫描原始数组的空间。

大同小异

排颜色follow up

给定一个有n个对象(包括k种不同的颜色,并按照1到k进行编号)的数组,将对象进行分类使相同颜色的对象相邻,并按照1,2,…k的顺序进行排序。

给出colors=[3, 2, 2, 1, 4],k=4, 你的代码应该在操作使得数组变成[1, 2, 2, 3, 4]

class Solution {    /**     * @param colors: A list of integer     * @param k: An integer     * @return: nothing     */    public void sortColors2(int[] colors, int k) {        // write your code here        if (colors == null || colors.length == 0 || k <= 0){            return;        }        int[] count = new int[k + 1];        for (int i = 0; i < colors.length; i++){            count[colors[i]]++;        }        int index = 0;        for (int i = 0; i < count.length; i++){            while (count[i]-- > 0){                colors[index++] = i;            }        }    }}

这个地方没有0,所以要自己补统计0的个数

0 0
原创粉丝点击