【题解】力扣703.数据流中的第K大元素

题目来源

703. 数据流中的第 K 大元素

题目描述:

设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。

请实现 KthLargest 类:

  • KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。

  • int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。

思路及算法

方法一:优先队列

可以使用一个大小为\(k\)的优先队列来存储前\(k\)大的元素,其中优先队列的队头为队列中最小的元素,也就是第\(k\)大的元素

在单次操作中,先将元素加入到优先队列中,如果当前队列的长度大于\(k\),则将队头元素弹出,以保证优先队列的大小为\(k\)

class KthLargest {
	PriorityQueue<Integer> heap;	// 声明
    int k = 0;
    public KthLargest(int k, int[] nums) {	// 构造方法
		this.k = k;
        heap = new PriorithQueue<Integer>(k);	// 实例化优先队列对象,分配对象
        
        for(int i : nums)
            add(i);
    }
    
    public int add(int val) {
		if(heap.size() < k){
            heap.offer(val);	// 将val插入到优先队列中
        }else if (heap.peek() < val){	// 如果头部元素小于当前要插入的值
            heap.poll();	// 检索并删除队列的头部,如果头部为空,则返回null
            heap.offer(val);
        }
        
        return heap.peek();	// 检索但不删除队列的头部,如果头部为空,则放回null
    }
}

/**
 * Your KthLargest object will be instantiated and called as such:
 * KthLargest obj = new KthLargest(k, nums);
 * int param_1 = obj.add(val);
 */

方法二:堆排序

  1. 使用大小为 K 的小根堆,在初始化的时候,保证堆中的元素个数不超过 K
  2. 在每次 add() 的时候,将新元素 push() 到堆中,如果此时堆中的元素超过了 K,那么需要把堆中的最小元素(堆顶)pop() 出来。
  3. 此时堆中的最小元素(堆顶)就是整个数据流中的第 K 大元素。
class KthLargest {
    // 堆排序解法 - 维护一个大小为k的小根堆, 若当前要插入的数小于等于堆顶元素, 则丢弃; 否则插入, 可以直接插入到堆顶, 在进行调整. 堆顶元素保存了第k大元素.
    // 创建一个小根堆
    int[] heap;
    int size = 0;
    int count = 0;
    public KthLargest(int k, int[] nums) {	// 构造方法
        heap = new int[k];
        count = k;

        // 初始化一个大小为k的小根堆
        for (int i = 0; i < nums.length; i++) {
            add(nums[i]);
        }

    }
    
    public int add(int val) {
        
        if (size < count) {
            heap[size] = val;
            up(size);
            size++;
        } else if (heap[0] < val) {
            heap[0] = val;
            down(0);
        }

        return heap[0];
    }

    // 自上向下调整堆,下沉
    public void down (int u) {
        int t = u;
        if (2 * u + 1 < size && heap[2 * u + 1] < heap[t])
            t = 2 * u + 1;
        if (2 * u + 2 < size && heap[2 * u + 2] < heap[t])
            t = 2 * u + 2;
        if (t != u) {
            int temp = heap[u];
            heap[u] = heap[t];
            heap[t] = temp;
            down (t);
        }
    }

    // 自下向上调整堆,上升
    public void up (int u) {
        // 存在父亲节点, 并且父亲节点的值大于当前值, 则进行交换
        while ((int)(Math.ceil(u / 2.0) - 1) >= 0 && heap[(int)Math.ceil(u / 2.0) - 1] > heap[u]) {
            int p = (int)(Math.ceil(u / 2.0) - 1);
            int temp = heap[u];
            heap[u] = heap[p];
            heap[p] = temp;
            u = p;
        }
    }
}

/**
 * Your KthLargest object will be instantiated and called as such:
 * KthLargest obj = new KthLargest(k, nums);
 * int param_1 = obj.add(val);
 */

参考来源

  1. Pinkman🍑
  2. 力扣官方题解:数据流中的第K大元素
posted @ 2021-02-16 11:39  zzzzzy2k  阅读(71)  评论(0编辑  收藏  举报