剑指Offer——面试题30:最小的K个数
题目:输入N个数字,找出其中最小的K个数。
思路:维护一个数组KMin,长度为K,存放最小的K个数。遍历原始数组的过程中,如果KMin不满,就直接在后边插入新的数字;如果KMin满了,就要找到其中最大的数字,和当前遍历原始数组时遇到的数字进行比较,决定是否更新。由于每次都要获得KMin中最大的数字,所以可以把KMin用一个大顶堆来实现,当KMin满了的时候,就建堆,之后在每次遍历时,都用当前遍历得到的元素与KMin的堆顶比较,决定是否更新,如果更新,就维护堆。其中建堆过程和维护堆的过程共用一个函数AdjustHeap来描述。算法用C/C++实现。
void AdjustHeap(int* const arr, const int length){ for(int i = length / 2 - 1; i >= 0; i--){ int temp = arr[i]; int k = 0; for(int j = i * 2 + 1; j < length; j = k * 2 + 1){ k = j; if(j + 1 < length) k = arr[j] > arr[j + 1] ? j : j + 1; if(arr[k] > arr[i]){ arr[(j - 1) / 2] = arr[k]; arr[k] = temp; } else break; } } } int* GetKMin(int* const arr, const int length, const int K){ if(K <= 0) return NULL; int* KMin = new int[K]; for(int i = 0; i < length; i++){ if(i <= K) KMin[i] = arr[i]; if(i == K) AdjustHeap(KMin, K); if(i > K) if(arr[i] < KMin[0]){ KMin[0] = arr[i]; AdjustHeap(KMin, K); } } return KMin; }
测试代码:
int main(){ const int K = 5; const int B = 10; static int TestBase[B] = {6, 2, 20, 13, 9, 11, 7, 5, 1, 8}; static int TestBase2[B] = {6, 2, 20, 13, 9, 11, 7, 5, 1, 6}; int i = 0; for(i = 0; i < B; i++) cout << TestBase[i] << " "; cout << endl; int * KMin = GetKMin(TestBase, B, K); if(KMin) for(i = 0; i < K && i < B; i++) cout << KMin[i] << " "; cout << endl; return 0; }
测试用例:
K = 5, B = 10;
K = 1, B = 10;
K = 0, B = 10;
K = -1, B = 10;
K = 15, B = 10;
还可以使用TestBase和TestBase2分别测试原始数组中是否有重复元素。