703. 数据流中的第 K 大元素(优先队列:小根堆)

该博客介绍了如何使用小根堆解决数据流中找到第K大元素的问题。通过创建一个大小为K的小根堆,每次添加元素时,堆会自动保持排序,当堆满时,堆顶元素即为第K大的元素。这种方法避免了频繁排序,实现了O(n*logk)的时间复杂度,节省了空间。
摘要由CSDN通过智能技术生成

数据流中的第 K 大元素

设计一个找到数据流中第 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); // return 4
kthLargest.add(5); // return 5
kthLargest.add(10); // return 5
kthLargest.add(9); // return 8
kthLargest.add(4); // return 8


解题思路

如果该题使用数组的话,当每次调用 add() 函数时,向数组中添加一个元素,然后调用 sort() 函数进行排序,返回排序后数组的第 K 个数字。该做法在每次调用 add() 函数时的时间复杂度为 O(K*log(K)),该时间复杂度太高,当 K 很大且 add() 调用次数太多的时候,一定会超时。
使用数组最大的问题:数组无法在不调用 sort() 函数的情况下自动排序,这会导致时间复杂度过高。

有什么数据结构能够自带排序功能呢?答案是:
大根堆和小根堆

  1. 使用大小为 K 的小根堆,初始化时,要使堆中的元素个数不超过 K 个。
  2. 在每次调用 add() 函数时,要将新元素 val 添加到堆中(此时,堆会自动的排序,形成小根堆),如果此时堆中的元素个数超过了 K 个,则要把堆中的最小元素(堆顶)从当前堆中拿出来。
  3. 此时堆中的最小元素(堆顶)就是整个数据流中的第 K 大的元素(因为小根堆中保留的一直是堆中的前 K 大的元素,而此时堆的大小为 K,所以堆顶元素就是整个数据流中第 K 大元素)。

代码

class KthLargest {

    //小根堆
    /*
	PriorityQueue是基于优先堆的一个无界队列,
	这个优先队列中的元素可以默认自然排序或者通过提供的Comparator(比较器)在队列实例化的时排序。
	用优先队列可实现大根堆和小根堆(默认是小根堆)
	*/

    PriorityQueue<Integer> pq;//声明
    int k;

    public KthLargest(int k, int[] nums) {

        this.k = k;
        pq = new PriorityQueue<Integer>();//分配内存

        //把nums数组遍历一遍
        for (int x : nums) {

            add(x);
        }
    }
    
    //添加函数
    public int add(int val) {

        pq.offer(val);//offer函数将给定元素(val)添加到此PriorityQueue中
        if (pq.size() > k) {

            /*
            对于poll()方法,它将检索队列的head元素,然后删除队列的head元素。
                如果队列为空,则它将返回null,但不会引发异常。
            */
            pq.poll();
        }
        //用于返回第一个元素,而不从此PriorityQueue中删除一个元素。
        return pq.peek();
    }
}

时间复杂度:O(n * logk),其中 n 为初始化时 nums 的长度。
空间复杂度:O(k),需要使用优先队列存储前 k 大的元素。


参考资料:
面试题警告:经典 TopK ,本题需要重点学习
数据流中的第 K 大元素

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值