703. Kth Largest Element in a Stream(python+cpp)
題目:
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
。