描述
给出一个长度为n的可能有重复值的数组,找出其中不去重的最小的k个数
例:
输入:[4,5,1,6,2,7,3,8],4
返回:[1,2,3,4]
要求:空间O(N),时间O(nlogn)
解题思路
方法一:直接排序取前k个值
方法二:堆排序
堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。首先简单了解下堆结构。
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:
该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
队列那么先要包含头文件#include , 他和queue不同的就在于我们可以自定义其中数据的优先级, 让优先级高的排在队列前面,优先出队
优先队列具有队列的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的
和队列基本操作相同:
top 访问队头元素
empty 队列是否为空
size 返回队列内元素个数
push 插入元素到队尾 (并排序)
emplace 原地构造一个元素并插入队列
pop 弹出队头元素
swap 交换内容
//升序队列
priority_queue <int,vector,greater > q;
//降序队列
priority_queue <int,vector,less >q;
//对于基础类型 默认是大顶堆,降序队列
priority_queue a;
//等同于 priority_queue<int, vector, less > a;
建立一个容量为k的大根堆(降序)的优先队列。遍历一遍元素,如果队列大小<k,就直接入队(入队后自动排序),否则,将当前元素和队顶元素相比,如果队顶元素大,则出队,将当前元素入队。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> ret;
if (k==0 || k > input.size()) return ret;
priority_queue<int, vector<int>> pq;
for (const int val : input) {
if (pq.size() < k) {
pq.push(val);
}
else {
if (val < pq.top()) {
pq.pop();
pq.push(val);
}
}
}
while (!pq.empty()) {
ret.push_back(pq.top());
pq.pop();
}
reverse(ret.begin(),ret.end());
return ret;
}
};
时间复杂度:O(nlongk), 插入容量为k的大根堆时间复杂度为O(longk), 一共遍历n个元素
空间复杂度:O(k)