Leetcode: 寻找数据流中的第K大元素

题目:

设计一个找到数据流中第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

解题思路:

利用优先队列的方式,即用一个二叉堆(最小堆),保留的是前k大的元素,则堆顶则是我们要求的第k大元素。将数据流加入优先队列中,每次判断堆的元素是否等于k,如果等于k,在不需要加入元素。

当加入的元素比堆顶的元素还要大,则表示堆顶的元素不是前k的元素中的第k大的元素,则将堆顶元素移除,然后将新加入的元素加入堆中,经过自我调整后,此时堆顶的元素即可第k大的元素。

图解: 

假设数组为:{1,3, 5, 6, 8},则第k大假设k=4,即第四大元素,则我们此时的堆如下:

此时,当数据流继续加入元素4,则此时数组为{1,3, 5, 6, 8, 4},则4大于堆顶元素,则我们要将堆顶元素3移除,并且将4插入到堆中去。

删除操作:

将3跟最后一个元素 交换

最小堆的自我调整,将8进行“下浮”操作

删除完毕

插入操作:

将插入元素4放到堆中的最后一个元素

将4进行上浮操作:

此时,4则是我们额第k大的元素

代码:

/**
 * 描述: 优先队列题目: 寻找数据流中的第K大元素
 *   思路: 基于最小堆实现
 *
 * @author pengjie_yao
 * @date 2019/7/18 21:20
 */
public class PriortyQueueByK {
    final PriorityQueue<Integer> priorityQueue;

    final int k;

    public PriortyQueueByK(int k, int[] array) {
        this.k = k;
        priorityQueue = new PriorityQueue<>(k);
        for (int i : array) {
            add(i);
        }
    }

    /**
     *  新增堆顶元素
     * @param n
     * @return
     */
    public int add(int n) {
        // 堆的元素个数小于k个元素的时候,加入堆
        if (priorityQueue.size() < k) {
            priorityQueue.offer(n);
        } else if (priorityQueue.peek() < n) {
            // 堆顶的元素小于要加入的元素,则表示堆顶的元素不是第k大的元素,则将堆顶元素去掉,新元素加入
            priorityQueue.poll();
            priorityQueue.offer(n);
        }
        // 返回堆顶元素
        return priorityQueue.peek();
    }



    public static void main(String[] args) {
        int[] array = new int[]{1, 2, 3, 5, 4, 20, 15};
        PriortyQueueByK priorityQueue = new PriortyQueueByK(1, array);
        // return 21
        priorityQueue.add(21);
        // return 22
        priorityQueue.add(22);
        // return 34
        priorityQueue.add(34);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值