题目描述:
输入整数数组 arr ,找出其中最小的 k 个数。
举例说明:
算法描述:
1、将数组的前k个数建大堆(向下调整算法)
2、从数组中第k+1个数开始与堆顶元素相比。若比堆顶元素小,二者交换,然后再对该堆进行一次向下调整算法。循环此过程。
3、最终,最小的k个数即为堆中的所有数字组成。
具体步骤如下图举例所示。
代码实现:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
void AdjustDown(int* a,int n,int root)
{
int parent = root;
int child = parent*2 + 1;
while(child<n)
{
if(child+1<n&&a[child]<a[child+1])
{
++child;
}
if(a[child] > a[parent])
{
int temp = a[child];
a[child] = a[parent];
a[parent] = temp;
parent = child;
child = parent*2 + 1;
}
else
{
break;
}
}
}
int* getLeastNumbers(int* arr, int arrSize, int k, int* returnSize){
*returnSize = k;
if(k==0)
{
return NULL;
}
int* retArr = (int*)malloc(sizeof(int)*k);
//建k个数的大堆
int i ,j;
for(i = 0;i < k; i++)
{
retArr[i] = arr[i];
}
for(i=(k-1-1)/2; i >= 0; i--)
{
AdjustDown(retArr,k,i);
}
for(j=k;j<arrSize;j++)//从数组中第k+1个数开始与堆顶元素相比
{
if(arr[j]<retArr[0])
{
retArr[0] = arr[j];//覆盖掉
AdjustDown(retArr,k,0);
}
}
return retArr;
}
优点分析:
TopK问题
1、时间复杂度为O(N*logK)
2、同直接进行堆排序或快速排序相比要快的多
3、利用了大堆的特性,将大的数“浮”在最上面,小的数都“沉”在下面,很容易的选出了最小的k个数。