题目:
设计一个找到数据流中第 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 ) ;
kthLargest. add ( 5 ) ;
kthLargest. add ( 10 ) ;
kthLargest. add ( 9 ) ;
kthLargest. add ( 4 ) ;
提示:
1 <= k <= 104
0 <= nums. length <= 104
- 104 <= nums[ i] <= 104
- 104 <= val <= 104
最多调用 add 方法 104 次
题目数据保证,在查找第 k 大元素时,数组中至少有 k 个元素
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -
思路:
此题要求我们求数据流中的 TopK ,这是很常见的题目,现在我们来想一下暴力解法:
设置一个数组,将 add ( ) 后的元素都存放在数组中。
每次 add ( ) 之后,我们都对数组进行排序,然后返回 TopK 元素。
显然,上面这种是不太现实的,每次都要对数组进行排序,时间复杂度太高
。暴力解法的问题所在是:数组这种数据结构是没有自带排序的功能的,
所以,我们目前就是需要一种自带排序功能的数据结构——堆。
在大根堆中,父节点的值比每一个子节点的值都要大。
在小根堆中,父节点的值比每一个子节点的值都要小。
本题,我们使用小根堆,至于为什么使用小根堆,看完解题思路你就知道了:
初始化,将所有的元素都插入堆中。
每次 add ( ) 的时候,将新元素插入到堆中,如果此时堆中的元素超过了 K ,那
么需要把堆中的最小元素(堆顶)删除。
此时堆中的最小元素(堆顶)就是整个数据流中的第 K 大元素。
Java 中的 PriorityQueue 就是使用堆实现的。
PriorityQueue < Integer > minHeap = new PriorityQueue < Integer > ( ) ;
PriorityQueue < Integer > maxHeap = new PriorityQueue < Integer > ( 11 , new Comparator < Integer > ( ) {
@Override
public int compare ( Integer i1, Integer i2) {
return i2- i1;
}
} ) ;
-- -- -- -- -- -- -- -- -- -- -- -- --
class KthLargest {
private PriorityQueue < Integer > heap;
private int k;
public KthLargest ( int k, int [ ] nums) {
this . k = k;
heap = new PriorityQueue < > ( k) ;
for ( int num : nums) {
heap. add ( num) ;
}
}
public int add ( int val) {
heap. add ( val) ;
while ( heap. size ( ) > k) {
heap. poll ( ) ;
}
return heap. peek ( ) ;
}
}
LC