LeetCode上的那些计数排序

计数排序

复杂度分析:

​ 时间复杂度:O(n+k),即线性时间,k为给定数据中的最大值(k为整数范围),而其他的排序方法则最好的情况才是O(nlgn)。这是计数排序用空间换取时间的便利,也是计数排序只在特定情况才能使用的缺陷。

​ 空间复杂度:总的空间复杂度为O(n+k),因为用到了另一个数组O(k)用于存储。

看完此文可以在力扣上轻松解决以下问题:

274. H 指数

561. 数组拆分 I

912. 排序数组

1051. 高度检查器

1122. 数组的相对排序

剑指 Offer II 075. 数组相对排序

​ 偶然间在力扣上看到一排序的题,便点了进去。912. 排序数组

题目意思很简单将数组升序排列,如果是为了快速解题的话,直接出结果,用sort()方法一步就行,但看了看难度,怎么是个中等题。于是在题库的归类里赫然看到“计数排序”这四个大字。那便来学习下计数排序

​ 计数排序英文名:Counting Sort,顾名思义。注意这里有个中文读音很像的**“基数排序”**,两者是有所不同的,基数排序英文是:Radix sort,radix英文中意思是基数,而基数在数学中是集合论的一个概念,两个能够建立元素间一一对应的集合称为互相对等集合,基数排序这里暂且不提。

1.算法思想

​ 首先计数排序从字面意思上就可以看出来,计算数字。这是一个稳定的非比较排序算法。一种基于特定范围内的键值的排序。通过计算具有不同键值的对象的数量,然后来得出每个对象在输出序列中的位置。有另一种不借助额外的存储空间的,只使用计数数组作为辅助存储,但是这种修改后的并不稳定。


​ In computer science, counting sort is an algorithm for sorting a collection of objects according to keys that are small positive integers; that is, it is an integer sorting algorithm. ——from wikipedia


2.排序思路

​ 通过数组实现,将原数组中整数的值,作为索引,在另一个数组上对应的索引累加。也就是说,不通过比较,而是索引下标确定值的位置。然后遍历目标数组,依次输出就是排序后的结果。一般用于比较小的正整数,太大会造成目标数组空间的浪费。keys 可以理解为 index的键, 既然将值作为索引,那负数是不支持的。但是为了对负数也能够排序,在初始化数组空间的时候,可以通过加上一个固定的值(max-min+1),来实现对负数的取正。

3.实际应用

​ 下面以力扣的912.排序数组为例:

示例:

Input:
[1, 3, 2, 8, 5, 1, 5, 1, 2, 7]
Output:
[1, 1, 1, 2, 2, 3, 5, 5, 7, 8]

首先需要初始化三个变量,max用于计算数据最大值,dp初始化为空数组用于输出,ans用于构建计数数组

var sortArray = function(nums) {
    let max=Math.max(...nums)
    let dp =[]
    let ans=new Array(max+1).fill(0)
    for(let d of nums){
        ans[d]++
    }
    for(var k = 0; k <= max; k++){
        while(ans[k]-- > 0){
            dp.push(k);
        }
    }
    return dp
};

​ 这个时候就算是写完了,但是拿去测试的时候你会发现报错了。为什么呢?题目中给出的数据范围是:[-50000,50000],这时候你看完了前面的内容可能会想了,计数排序无法适用于负数的原因就是将值作为索引,那么索引一定不能是负的。出错的原因就在这!前面也提到了有解决的办法,其实很简单。只需要稍加修改.

​ 添加变量min用于计算数据中的最小值,在数组初始化的时候,空间大小初始化为max-min+1,也就是间接的将负数对应的索引”取正“。这里在后面的几个循环中需要注意循环截止的条件!

var sortArray = function(nums) {
    let max=Math.max(...nums)
    let min=Math.min(...nums)
    let dp =[]
    let ans=new Array(max-min+1).fill(0)
    for(let d of nums){
        ans[d-min]++
    }
    for(var k = 0; k <= max-min+1; k++){
        while(ans[k]-- > 0){
            dp.push(k+min);
        }
    }
    return dp
};

​ 写到此,计数排序的代码已经完成了,有兴趣的可以试试原地排序。

​ 特别需要提到的,在翻阅了很多资料中,并没有给出过Js的计数排序模板,Js的数组也不是实际意义上的数组,而是对象,还有很多方法可以用来优化以上代码,但思路始终是这个思路,这里暂且不提。

全文代码通过JavaScript实现

参考资料:

wiki/Counting_sort
leetcode-cn.com
javascript-algorithms

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值