输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
思路
通过位置一个大小为k的大顶堆,如果数组中有小于堆顶的数值则将其加入大顶堆中,然后进行堆调整,
最后大小为k的大顶堆便就是题目所求
class Solution {
public:
// 大顶堆调整
void maxHeapify(vector<int>&arr, int start, int end){
int parent= start;
int child= 2*parent+ 1;
while(child< end){
// 挑子节点中值最大的那个
if(child+ 1< end&& arr[child]< arr[child+ 1])
child++;
// 父节点大于子节点说明对调整完毕
if(arr[parent]>= arr[child])
return;
else{
// 交换子节点和父节点,并将子节点的下标赋值给parent
swap(arr[parent], arr[child]);
parent= child;
child= 2*parent+ 1;
}
}
}
vector<int> getLeastNumbers(vector<int>& arr, int k) {
// 边界判断
if(arr.empty()) return arr;
// 初始化一个大小为k的大顶堆
for(int i= k/2- 1; i>= 0; i--){
maxHeapify(arr, i, k);
}
int size= arr.size();
// 继续遍历数组,如果大顶堆堆顶大于位置i的值,则替换堆顶然后进行对调整
for(int i= k; i< size; i++){
if(arr[i]< arr[0]){
arr[0]= arr[i];
maxHeapify(arr, 0, k);
}
}
// 返回前k个数
return vector(arr.begin(), arr.begin()+ k);
}
};
为了熟悉一下快排,写了个快排的版本,从leetcode的结果来看,时间上上面的大顶堆解法优,也有可能是我没对快排进行优化。
大致思路是利用了快排中每次切分都可以确定一个数在排好序的数组中的真正位置,
每次切分后确定位置的数值value的左边的数肯定小于value,其右边的数肯定大于value;
所有如果value的位置刚好是k-1(数组从0开始),那么在k左边的数就是题目所求
class Solution {
public:
// 切分
int patition(vector<int>& arr, int l, int h){
int guard= arr[l];
while(l< h){
while(l< h&& arr[h]>= guard)
h--;
arr[l]= arr[h];
while(l< h&& arr[l]<= guard)
l++;
arr[h]= arr[l];
}
arr[l]= guard;
return l;
}
void qSort(vector<int>& arr, int k, int l, int h){
if(l>= h)
return;
int mid= patition(arr, l, h);
// 当确定位置的数刚好是第k个
if(mid== k- 1)
return;
qSort(arr, k, l, mid- 1);
qSort(arr, k, mid+ 1, h);
}
vector<int> getLeastNumbers(vector<int>& arr, int k) {
// 边界判断
if(arr.empty()) return arr;
qSort(arr, k, 0, (int)arr.size()- 1);
return vector(arr.begin(), arr.begin()+ k);
}
};