C++--问题19--查找数组前K个最小值的算法
解决这个问题的初思路,都能想到先排序,然后前K个最小值的算法就出来了。排序用快速和堆排序,有几种具体的方法如下:
1. 快速排序,找前K
对数组进行排序,然后前K个元素就是需要查找的元素,排序的方法可以采用快速排序。
但是我们知道在快速排序中如果已经是有序的数组,采用快速排序的时间复杂度是O(N^2)。
为了解决这种问题,有两种解决办法,
(1)随机选择一个数组值pivot作为基准,将数组分为S1 <= pivot 和 S2 > pivot;
(2)采用随机选择三个元素,然后取中间值作为基准,就能避免快速算法的最差时间复杂度。
2.先划分再比较K与S1个数的大小,为了省去不必要的排序,再快排找前K
既然是选择前K个对象,那么就没必要对所有的对象进行排序,可以采用快速选择的思想获得前K个对象。
(1)首先采用快速排序的集合划分方法划分集合:S1,pivot,S2,满足S1 <= pivot 和 S2 > pivot;
(2)然后比较K是否小于S1的个数,
如果小于,则直接对S1进行快速排序
,如果K的个数超过S1,那么对S2进行快速排序;
(3)排序完成之后,取数组的前K个元素就是数组的前K个最小值。
这种实现方法肯定比第一种的全快速排序要更快速。
3.创建K次的最小堆
将数组转换为最小堆的情况,根据最小堆的特性,第一个元素肯定就是数组中的最小值,这时候我们可以将元素保存起来,然后将最后一个元素提升到第一个元素,重新构建最小堆,这样进行K次的最小堆创建,就找到了前K个最小值。这是运用了最小堆的特性,实质上是
最小堆的删除实现方法
。这种算法的好处是实现了数组的原地排序,并不需要额外的内存空间。
4.创建最大堆
这种思想有点类似桶排序。
(1)给定一个K个大小的数组b,然后复制数组a中的前K个数到数组b中;
(2)将这K个数当成数组a的前K个最小值,对数组b创建最大堆;
(3)这时候再去比较数组a中的其他元素,如果其他元素小于数组b的最大值(堆顶),则将堆顶的值进行替换,并重新创建最大堆。
(4)这样遍历一次数组就找到了前K个最小元素。这种方法运用了额外的内存空间,特别当选择的K值比较大时,这种方法有待于权衡一下。
这种方法对于
海量数据来说是有较好的作用
,对于海量数据不能全部存放在内存中,这时候创建一个较小的数组空间,然后创建最大堆,从硬盘中读取其他的数据,进而实现前K个数据的查找。