703. 数据流中的第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
说明:
你可以假设 nums 的长度≥ k-1 且k ≥ 1。

说明

由于想练习下堆的操作,于是在leetcode中直接索引 堆 关键字 找到该题,所以思路方面没多考虑就选择了堆来完成此题。

面试常见题 100亿个数里找最大的前K个数 亦采用此思路。

思路

思路清晰,构建一个容量为k的小根堆(即堆头节点最小),因为题目是求第k大的元素,构建小根堆后即为堆头节点即为所求。每次添加元素都调整堆(替换堆头节点)

具体步骤:

1 使用nums的前k个元素构建一个小根堆(createMinHeap),即数组a。

        这步有一个需要考虑的情况nums.length==k-1(因为题目只限定nums.length>=k-1),我采取的方法是先复制nums数组到a数组,然后a的最后一个元素直接填充为Integer.MIN_VALUE;

2 将nums后边的元素添加到堆中(addNode);

3 每添加一个节点就进行一次addNode,并返回堆顶元素,即a[0];

代码

class KthLargest {

    private int[] a = null;

    public KthLargest(int k, int[] nums) {
        a = new int[k];
        if(nums.length>k-1){
            System.arraycopy(nums,0,a,0,k);
        }else{
            System.arraycopy(nums,0,a,0,k-1);
            a[k-1] = Integer.MIN_VALUE;
        }
        
        createMinHeap(k,nums);
    }
    
    public void createMinHeap(int k,int[] nums){
        for(int i=k/2-1;i>=0;i--){
            swapChild(i,k);
        }
        for(int i=k;i<nums.length;i++){
            addNode(nums[i]);
        }

    }

    public void swapChild(int i,int k){
        int min = a[i];
        int minIndex = i;
        if(i*2+1<k&&min>a[i*2+1]){
            min = a[i*2+1];
            minIndex = i*2+1;
        }
        if(i*2+2<k&&min>a[i*2+2]){
            min = a[i*2+2];
            minIndex = i*2+2;
        }
        if(minIndex!=i){
            swap(a,i,minIndex);
            swapChild(minIndex,k);
        }
    }

    public void addNode(int val){
        if(a[0]<val){
            a[0] = val;
            swapChild(0,a.length);
        }
    }

    public void swap(int[] nums,int i,int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    public int add(int val) {
        addNode(val);
        return a[0];
    }
}

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

附:若题目的给定数据是固定的(如leetcode 215. 数组中的第K个最大元素)采用快速排序也是一种不错的思路。

堆排序的优势在于能够将占用的内存空间维持在O(k),很适合数据量很大,k很小的场景。另外对于类似此题的动态增加数据时并重新更新第k大元素很方便。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值