原题:703. 数据流中的第 K 大元素
设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。
请实现 KthLargest 类:
KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。
int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。
示例:
输入:
["KthLargest", "add", "add", "add", "add", "add"]
[[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]
输出:
[null, 4, 5, 5, 8, 8]
解释:
KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]);
kthLargest.add(3); // return 4
kthLargest.add(5); // return 5
kthLargest.add(10); // return 5
kthLargest.add(9); // return 8
kthLargest.add(4); // return 8
提示:
1 <= k <= 104
0 <= nums.length <= 104
-104 <= nums[i] <= 104
-104 <= val <= 104
最多调用 add 方法 104 次
题目数据保证,在查找第 k 大元素时,数组中至少有 k 个元素
显而易见的,找数据流中的第k大元素,是需要排序的。如果不使用任何的数据结构,那么首先对初始的输入nums进行排序,然后依次对插入的数据寻找位置后插入nums中,但实现起来比较慢,效果也并不是很客观。在这里,可以利用multiset的特性,即任意顺序插入的multiset始终是保持有序的(从小到大),并且可以容许数字重复出现,例如依次插入4、5、8、2,在multiset中的顺序为2、4、5、8,这样节省了手动初始排序和后序插入排序的时间。因为要输出第k大元素,那么这个multiset的大小控制为k即可,当插入数据后multiset的大小超过k,那么删除multiset的第一个元素就实现了控制k的大小,并且现在这个multiset的k个元素是输入数据流中最大的k个。
所以,在KthLargest中,根据初始的nums依次插入muliset中,如果大小超过k,就删除第一个元素。同理,在add中,先插入val,如果大于k,就删除第一个元素(可能初始的数据流大小小于k,所以需要先判断再删除,否则multiset的大小始终小于k),然后再返回删除后的第一个元素即可。在add函数中需要知道大小k,但是在给定的输入参数中并没有,所以定义了一个全局变量kk,来保存k的值。
class KthLargest {
multiset <int> topk;
int kk;
public:
KthLargest(int k, vector<int>& nums) {
kk=k;
for(int i=0;i<nums.size();i++){
topk.insert(nums[i]);
if(topk.size()>k)
topk.erase(topk.begin());
}
}
int add(int val) {
topk.insert(val);
if(topk.size()>kk)
topk.erase(topk.begin());
return *topk.begin();
}
};
/**
* Your KthLargest object will be instantiated and called as such:
* KthLargest* obj = new KthLargest(k, nums);
* int param_1 = obj->add(val);
*/