88 前K大数 II(Top k Largest Numbers II)

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 源码

细节:

  1. 使用最小堆优先序列,维护一个容量为k的优先序列,插入的数超过容量时,抛掉堆顶元素。
  2. 取前k个数的时候,预先创建一个与堆大小相同的数组用于存放结果,逐个从堆顶弹出最大数倒序放入数组。
  3. 取出结果之后,还需要将取出的数放回优先序列中。

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;
    }
};

猜你喜欢

转载自blog.csdn.net/SeeDoubleU/article/details/124657757
今日推荐