题目链接:https://leetcode-cn.com/problems/kth-largest-element-in-a-stream/submissions/
题目介绍:
设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。
你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。
示例:
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
说明:
你可以假设 nums 的长度≥ k-1 且k ≥ 1。
解题思路:
我分为三种解题方法来解决这个问题。
一、使用数组
- 将K个数依次从小到大的顺序放在数组中,数组的第一个数就是第K个数
- 如果要插入的数小于第一个数,就直接返回;如果大于,就插入,重新排序,返回第一个数
- 重复上一个步骤,直至所有的数完成操作
//数组维护前K大的元素
class KthLargest {
//将K个数按从小到大放在集合中
private List<Integer> list;
private int indexK;
public KthLargest(int k, int[] nums) {
list = new ArrayList<Integer>(k);
indexK = k;
Arrays.sort(nums);
int i = 0;
for (; i < k && i < nums.length ; i++) {
list.add(nums[nums.length -1 - i]);
}
while (i++ < k){
list.add(Integer.MIN_VALUE);
}
//对集合中的数从小到大排序
Collections.sort(list);
}
public int add(int val) {
//如果插入的值比最小的值小,就直接返回第K个数(即第一个数)
if (val < list.get(0)){
return list.get(0);
}else{
list.remove(0);
list.add(val);
}
Collections.sort(list);
return list.get(list.size() - indexK);
}
}
二、使用小顶堆完成队优先队列的模拟
- 构建小顶堆,并且root为我们需要的第K个数
- 如果元素不够K个,对剩余的元素填充最小值,然后对堆进行从下到上的堆化
- 添加元素时,与堆顶元素进行比较。如果大于,则进行替换,进行从上到下的堆化;如果小于,直接返回堆顶元素
//使用小顶堆维护前K大的元素
class KthLargest{
//最小堆
private int[] minHeap;
private int k;
public KthLargest(int k, int[] nums) {
this.k = k;
minHeap = new int[k];
Arrays.sort(nums);
int i = 0;
for (;i < k && i < nums.length;i++){
minHeap[i] = nums[nums.length - 1 - i];
}
//当数组不足以填充K个元素时,使用int的最小数填充满
while (i < k){
minHeap[i++] = Integer.MIN_VALUE;
}
//生成堆
generaterMinHeap();
}
//生成堆
private void generaterMinHeap() {
//从最后一个非叶子节点依次往前调整数
for (int i = k / 2 - 1;i >= 0;i--){
autoAdjustMinHeap(i,k);
}
}
private void autoAdjustMinHeap(int node, int lenth) {
int left = node*2 + 1;
int right = left + 1;
if (left > lenth - 1){
return;
}
int min = left;
if (right > lenth - 1){
min = left;
}else{
if (minHeap[min] > minHeap[right]){
min = right;
}
}
if (minHeap[min] > minHeap[node]){
return;
}
int t = minHeap[node];
minHeap[node] = minHeap[min];
minHeap[min] = t;
autoAdjustMinHeap(min,lenth);
}
public int add(int val) {
if (val < minHeap[0]){
return minHeap[0];
}
minHeap[0] = val;
autoAdjustMinHeap(0,k);
return minHeap[0];
}
}
三、使用jJava自带的优先队列
//用Java自带的优先队列实现
class KthLargest{
private PriorityQueue<Integer> minHeap;
private int k;
public KthLargest(int k, int[] nums) {
this.k = k;
minHeap = new PriorityQueue<Integer>(k);
for (int i = 0; i < nums.length; i++) {
add(nums[i]);
}
}
public int add(int val) {
if (minHeap.size() < k){
minHeap.offer(val);
}else if (minHeap.peek() < val){
minHeap.poll();
minHeap.offer(val);
}
return minHeap.peek();
}
}
代码地址:
https://github.com/Han-YLun/LeetCode/blob/master/Practice/src/Que703.java
文章为阿伦原创,如果文章有错的地方欢迎指正,大家互相交流。