题目:
Design a class to find the kth largest element in a stream. Note
that it is the kth largest element in the sorted order, not the kth
distinct element. YourKthLargest
class will have a constructor
which accepts an integerk
and an integer arraynums
, which
contains initial elements from the stream. For each call to the method
KthLargest.add, return the element representing thek
th largest
element in the stream.
Example:int k = 3; int[] arr = [4,5,8,2]; KthLargest kthLargest = new KthLargest(3, arr); kthLargest.add(3); // returns 4 kthLargest.add(5); // returns 5 kthLargest.add(10); // returns 5 kthLargest.add(9); // returns 8 kthLargest.add(4); // returns 8
Note:
You may assume thatnums
’ length ≥k-1
andk
≥ 1.
解释:
设计一个类,返回数据流中的最大的第k个元素。
注意是流中的,不是数组中的(215. Kth Largest Element in an Array(python+cpp)),如果是数组中的可以用快速排序中的partition做。
这道题目需要用堆来做
从小到大排序后总右往左数第k大的数字python的heap是小根堆,如果维持一个大小为k的heap的话,那么最小的数字(第一个数字)就是最终答案,后续输入的数字只需要和最小的数字nums[0]
相比就好,如果当前的堆的大小小于k,则直接将新元素入堆,否则,当前的堆的大小一定是k
(因为初始化的时候如果nums
的长度大于k,已经将堆裁剪为大小为k
的堆了),此时需要比较当前的val
和nums[0]
的关系,如果小于就不管,如果大于就弹出堆中的最小值,将val
入栈,python中可以直接用heapq.heapreplace(data,val)
,比先heap.pop()
再heapq.push()
的速度要快得多。
需要有一个变量记录当前堆的大小。
python代码:
class KthLargest(object):
def __init__(self, k, nums):
"""
:type k: int
:type nums: List[int]
"""
self.data=nums
self.k=k
self.size=len(nums)
heapq.heapify(self.data)
while self.size>k:
heapq.heappop(self.data)
self.size-=1
def add(self, val):
"""
:type val: int
:rtype: int
"""
if self.size<self.k:
heapq.heappush(self.data,val)
self.size+=1
elif val>self.data[0]:
heapq.heapreplace(self.data,val)
return self.data[0]
# Your KthLargest object will be instantiated and called as such:
# obj = KthLargest(k, nums)
# param_1 = obj.add(val)
c++代码:
#include <algorithm>
using namespace std;
class KthLargest {
public:
int heap_size=0;
int global_k=0;
vector<int>global_nums;
KthLargest(int k, vector<int> nums) {
global_k=k;
global_nums.assign(nums.begin(),nums.end());
heap_size=nums.size();
//c++默认是大根堆,这里需要用小根堆
make_heap(global_nums.begin(),global_nums.end(),greater<int>());
while (heap_size>k)
{
pop_heap(global_nums.begin(),global_nums.end(),greater<int>());
global_nums.pop_back();
heap_size--;
}
}
int add(int val) {
if (heap_size<global_k)
{
global_nums.push_back(val);
push_heap(global_nums.begin(),global_nums.end(),greater<int>());
heap_size++;
}
else if (val>global_nums[0])
{
pop_heap(global_nums.begin(),global_nums.end(),greater<int>());
global_nums[global_k-1]=val;
push_heap(global_nums.begin(),global_nums.end(),greater<int>());
}
return global_nums[0];
}
};
/**
* Your KthLargest object will be instantiated and called as such:
* KthLargest obj = new KthLargest(k, nums);
* int param_1 = obj.add(val);
*/
总结:
1.虽然heapq.heapify(nums)
以后nums
并不是顺序的,但是nums[0]
总是代表最小的元素(python heapq
默认是小根堆,c++的小根堆也是这样)
但是如果想实现一个大顶堆怎么办?
把在数据进堆的时候把所有数据都取相反数,出来的时候再取一下相反数就可以啦。
2. STL 堆操作
头文件是#include <algorithm>
一般用到这四个:make_heap()
、pop_heap()
、push_heap()
、sort_heap()
;
(1)make_heap()
构造堆
void make_heap(first_pointer,end_pointer,compare_function)
;
默认比较函数是(<),即最大堆。 函数的作用是将[begin,end)内的元素处理成堆的结构,要改成小根堆的时候,第三个参数变成greater<int>()
。
(2)push_heap()
添加元素到堆
void push_heap(first_pointer,end_pointer,compare_function)
;
新添加一个元素在末尾,然后重新调整堆序。该算法必须是在一个已经满足堆序的条件下。 先在vector的末尾添加元素,再调用push_heap
(3)pop_heap()
从堆中移出元素 ,
void pop_heap(first_pointer,end_pointer,compare_function)
;
把堆顶元素取出来,放到了数组或者是vector的末尾。 要取走,则可以使用底部容器(vector)提供的pop_back()函数。 先调用pop_heap再从vector中pop_back元素
(4)sort_heap()
对整个堆排序 ,排序之后的元素就不再是一个合法的堆了。
注意push_heap()和pop_heap()的时候也要传入compare_function
。