面试题40. 最小的k个数

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。 示例 1:

  1. 输入:arr = [3,2,1], k = 2
  2. 输出:[1,2] 或者 [2,1]

示例 2:

输入:arr = [0,1,2,1], k = 1
输出:[0]

限制:

  • 0 <= k <= arr.length <= 10000
  • 0 <= arr[i] <= 10000

代码实现

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
#include<stdlib.h>

void swap(int* aa,int* bb){
    int temp = *aa;
    *aa = *bb;
    *bb = temp;
}

//p及其孩子中,值最小者的下标
int getMin(int a[],int n,int p)
{
    int lc = p*2 + 1 ;
    int rc = p*2 + 2 ;
    int _min,smaller;
    if(rc < n) //有左右孩子
    {
        smaller = a[lc] < a[rc] ? lc:rc;
        _min = a[smaller] < a[p] ? smaller:p;
    }else{
        if(lc < n)//只有左孩子
        {
             _min = a[lc] < a[p] ? lc:p;
        }else{//没有左右孩子
            _min = p;
        }
    }
    return _min;
}
//单个结点的下滤操作
int perDownFilter(int a[],int n,int i)
{
    int j;//i及其孩子中值最小者下标
    while( i != (j = getMin(a,n,i)))//当 i = j时,即下面不再需要调整
    {
        swap(&a[i],&a[j]);//交换两者,并继续考察下降后的i
        i = j;

    }
    return i; //返回下滤操作抵达的最深的终结位置(亦i亦j)
}

void createHeap(int a[],int n)
{
    int cnt =0;
    for(int i = (n-2)/2;i>=0;i-- )
    {
        perDownFilter(a,n,i);//下滤内部结点
    }
}

int getHeapTop(int a[],int* n){
    if(a == NULL || *n <= 0)
        return 0;
    int res = a[0];
    a[0] = a[*n-1];//将最后一个元素放到堆顶
    perDownFilter(a,*n-1,0);//重新调整堆
    *n = *n-1;
    return res;
}

int* getLeastNumbers(int* arr, int arrSize, int k, int* returnSize){
    int* res = (int*)malloc(sizeof(int)*k);
    createHeap(arr,arrSize);
    int* heapSize = &arrSize;

    for(int i=0;i<k;i++){
        res[i] = getHeapTop(arr,heapSize);
    }
    *returnSize = k;
    return res;
}