leetcode
leetcode 651 ~ 700
数据流中的第 K 大元素

数据流中的第 K 大元素

难度:

标签:

题目描述

代码结果

运行时间: 58 ms, 内存: 20.0 MB


/*
 * Problem: Design a class to find the kth largest element in a stream of integers using Java Streams.
 *
 * Solution:
 * - The logic remains similar to the non-stream implementation, using a min-heap.
 * - The difference is in initialization, where we utilize Java Streams to populate the heap.
 * - The add method is implemented similarly, checking the size of the heap and the value to be added.
 */
import java.util.PriorityQueue;
import java.util.stream.IntStream;

public class KthLargest {
    private PriorityQueue<Integer> minHeap;
    private int k;

    public KthLargest(int k, int[] nums) {
        this.k = k;
        this.minHeap = new PriorityQueue<>(k);
        // Use Streams to add initial elements
        IntStream.of(nums).forEach(this::add);
    }

    public int add(int val) {
        if (minHeap.size() < k) {
            minHeap.offer(val);
        } else if (val > minHeap.peek()) {
            minHeap.poll();
            minHeap.offer(val);
        }
        return minHeap.peek();
    }
}

解释

方法:

这个题解的思路是使用一个最小堆来维护数据流中的前 k 个最大的元素。初始时,将 nums 中的元素加入堆中,如果堆的大小超过 k,则弹出堆顶元素(最小的元素),以保证堆中始终保留 k 个最大的元素。当新的元素 val 被添加到数据流中时,如果堆的大小小于 k,则直接将 val 加入堆中;如果 val 大于等于堆顶元素,则将堆顶元素替换为 val,然后调整堆。这样,堆顶元素始终是第 k 大的元素。

时间复杂度:

O(log k)

空间复杂度:

O(k)

代码细节讲解

🦆
在使用最小堆维护数据流中的前k个最大元素时,如何保证初始数组nums中的元素少于k个时的正确性?
当初始数组 nums 中的元素个数少于 k 时,最小堆会包含 nums 中所有元素。因为堆的大小没有被限定为 k,所以堆顶元素(最小元素)就是这个堆中的第 k 大的元素。在这种情况下,每次调用 add 方法时,如果添加的新元素使得堆的大小仍然不超过 k,则直接加入堆中;如果超过 k,则维持堆的大小为 k,确保堆顶元素是目前已知的第 k 大元素。这样通过逐步添加元素,直到堆的大小达到 k,堆顶的元素始终正确地表示第 k 大的元素。
🦆
如果数组nums中包含重复元素,这种最小堆的实现是否还能正确返回第k大的元素?
是的,最小堆的实现仍然可以正确处理包含重复元素的情况。在最小堆中,只要维持堆的大小为 k,堆顶元素就是第 k 大的元素,不论其中是否包含重复值。重复元素在堆中仅影响排序和堆顶元素的选择,但不影响实现第 k 大元素的功能。
🦆
为什么选择使用最小堆而不是最大堆来解决这个问题,最小堆在这个场景下有什么优势?
选择使用最小堆而不是最大堆的主要原因是最小堆可以更高效地维护数据流中的前 k 个最大元素。在最小堆中,堆顶是所有元素中最小的,这样可以保证堆中的其他元素都是比堆顶大的元素。当新的元素加入时,如果它不足以进入前 k 的范围(即比堆顶元素小),可以直接忽略;如果它足够大,可以替换堆顶元素并重新调整堆。这种方式比使用最大堆,然后维护一个大小为 k 的结构要有效,因为最大堆需要更多的操作来确定哪些元素需要被移除出前 k 大的列表。
🦆
在替换堆顶元素时,你使用了heapreplace方法。这个方法具体是如何工作的,与heappop后再heappush有什么区别?
heapreplace 方法是一个优化的堆操作,用于替换堆顶元素。它首先将堆顶元素移除,然后将新元素添加到堆顶,最后重新调整堆以保持堆的属性。这个方法比单独调用 heappop 移除堆顶元素和 heappush 添加新元素更加高效,因为它仅需要一次重新调整堆的操作,而不是两次。这种方法在连续替换堆顶元素的操作中,尤其在维护固定大小的堆时,能更快地达到平衡状态。

相关问题

数组中的第K个最大元素

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

 

示例 1:

输入: [3,2,1,5,6,4], k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

 

提示:

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 104