1 题目
题目:前K大数 II(Top k Largest Numbers II)
描述:实现一个数据结构,提供下面两个接口:
1.add(number) 添加一个元素;
2.topk() 返回此数据结构中最大的k个数字。
当我们创建数据结构时,k是给定的。
lintcode题号——545,难度——medium
样例1:
输入:
s = new Solution(3);
s.add(3)
s.add(10)
s.topk()
s.add(1000)
s.add(-99)
s.topk()
s.add(4)
s.topk()
s.add(100)
s.topk()
输出:
[10, 3]
[1000, 10, 3]
[1000, 10, 4]
[1000, 100, 10]
解释:
s = new Solution(3);
>> 生成了一个新的数据结构, 并且 k = 3.
s.add(3)
s.add(10)
s.topk()
>> 返回 [10, 3]
s.add(1000)
s.add(-99)
s.topk()
>> 返回 [1000, 10, 3]
s.add(4)
s.topk()
>> 返回 [1000, 10, 4]
s.add(100)
s.topk()
>> 返回 [1000, 100, 10]
样例2:
输入:
s = new Solution(1);
s.add(3)
s.add(10)
s.topk()
s.topk()
输出:
[10]
[10]
解释:
s = new Solution(1);
>> 生成了一个新的数据结构, 并且 k = 1.
s.add(3)
s.add(10)
s.topk()
>> 返回 [10]
s.topk()
>> 返回 [10]
2 解决方案
2.1 思路
数据结构的设计,要求支持插入和获取前k个大数,考虑使用最小堆优先序列,维护一个容量为k的优先序列,add操作向优先序列插入元素,topk操作逐个取出堆顶元素组合成结果即可。
2.2 时间复杂度
对于add操作,向容量为k的优先序列插入和删除元素,时间复杂度为O(log k);
对于topk操作,弹出所有元素耗时O(k * log k),再将元素都加回耗时O(k * log k)。
2.3 空间复杂度
使用了最小堆优先序列,容量为k,空间复杂度为O(k)。
3 源码
细节:
- 使用最小堆优先序列,维护一个容量为k的优先序列,插入的数超过容量时,抛掉堆顶元素。
- 取前k个数的时候,预先创建一个与堆大小相同的数组用于存放结果,逐个从堆顶弹出最大数倒序放入数组。
- 取出结果之后,还需要将取出的数放回优先序列中。
C++版本:
class Solution {
public:
int capacity = 0; // 优先序列的容量
priority_queue<int, vector<int>, greater<int>> numQueue; // 最小堆优先序列
/*
* @param k: An integer
*/Solution(int k) {
// do intialization if necessary
this->capacity = k;
}
/*
* @param num: Number to be added
* @return: nothing
*/
void add(int num) {
// write your code here
numQueue.push(num);
if (numQueue.size() > capacity) // 至维护大小为k的优先序列即可
{
numQueue.pop();
}
}
/*
* @return: Top k element
*/
vector<int> topk() {
// write your code here
vector<int> result(numQueue.size(), 0); // 创建与堆大小相同的结果集
for (int i = numQueue.size() - 1; i >= 0; i--)
{
result.at(i) = numQueue.top(); // 倒序组装结果
numQueue.pop(); // 每次都需要弹出堆顶
}
for (auto it : result)
{
numQueue.push(it); // 将弹出的数加回优先序列中
}
return result;
}
};