题目描述:链接
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
解题思想:参考链接
- 全局排序,O(n*lg(n))
- 局部排序,只排序TopK个数,O(n*k)
- 堆,TopK个数也不排序了,O(n*lg(k))
- 分治法,每个分支“都要”递归,例如:快速排序,O(n*lg(n))
- 减治法,“只要”递归一个分支,例如:二分查找O(lg(n)),随机选择O(n)
TopK的另一个解法:随机选择+partition本文采用堆,来维护一个长度为k的大根堆,其最顶端为这个堆里面最大的数
- 首先取输入数组nums[0…k-1],也就是数组的前k个数来构建大根堆top[0…k],则top[0]是大根堆的顶端,数值最大
- 然后对于nums[k…n],即数组后面的数进行遍历,如果当前数> top[0],则将top[0] = 当前数 并且 重新将数组top调整为大根堆。
- 最终遍历完成后,数组top[0…k]中保存的为数组最小的k个数并返回。
C++实现代码:
class Solution {
private:
void HeapAjust(vector<int>& nums, int parent, int len){
int tmp = nums[parent];
int child = 2*parent+1;
while(child < len){
if(child + 1 < len && nums[child] < nums[child + 1] ){
child++;
}
if(nums[child] < tmp){
break;
}
nums[parent] = nums[child];
parent = child;
child = 2*parent+1;
}
nums[parent] = tmp;
}
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
int l = arr.size();
if(k < 1 || l < 1) return vector<int>();
vector<int> topk(arr.begin(), arr.begin()+k);
for(int i = k / 2 - 1; i >=0; i--){
HeapAjust(topk, i, k);
}
for(int i = k; i < l; i++){
if(topk[0] > arr[i]){
topk[0] = arr[i];
HeapAjust(topk, 0, k);
}
}
return topk;
}
};
参考链接:
排序算法 | 堆排序
c++基础之vector、数组初始化