[LeetCode-703]数据流中的第K大元素

题目链接:https://leetcode-cn.com/problems/kth-largest-element-in-a-stream/submissions/


题目介绍:

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


解题思路:

    我分为三种解题方法来解决这个问题。

一、使用数组

  • 将K个数依次从小到大的顺序放在数组中,数组的第一个数就是第K个数
  • 如果要插入的数小于第一个数,就直接返回;如果大于,就插入,重新排序,返回第一个数
  • 重复上一个步骤,直至所有的数完成操作
//数组维护前K大的元素
 class KthLargest {

     //将K个数按从小到大放在集合中
     private List<Integer> list;
     private int indexK;
     
     public KthLargest(int k, int[] nums) {


         list = new ArrayList<Integer>(k);
         indexK = k;

         Arrays.sort(nums);

         int i = 0;
         for (; i < k && i < nums.length ; i++) {
             list.add(nums[nums.length -1 - i]);
         }

         while (i++ < k){
             list.add(Integer.MIN_VALUE);
         }

         //对集合中的数从小到大排序
         Collections.sort(list);
         
     }

     public int add(int val) {

         //如果插入的值比最小的值小,就直接返回第K个数(即第一个数)
         if (val < list.get(0)){
             return list.get(0);
         }else{
             list.remove(0);
             list.add(val);
         }

         Collections.sort(list);

         return  list.get(list.size() - indexK);
     }
 }

二、使用小顶堆完成队优先队列的模拟

  • 构建小顶堆,并且root为我们需要的第K个数
  • 如果元素不够K个,对剩余的元素填充最小值,然后对堆进行从下到上的堆化
  • 添加元素时,与堆顶元素进行比较。如果大于,则进行替换,进行从上到下的堆化;如果小于,直接返回堆顶元素
//使用小顶堆维护前K大的元素
 class KthLargest{

     //最小堆
     private int[] minHeap;
     private int k;

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

        this.k = k;
        minHeap = new int[k];
        Arrays.sort(nums);

        int i = 0;
        for (;i < k && i < nums.length;i++){
            minHeap[i] = nums[nums.length - 1 - i];
        }

        //当数组不足以填充K个元素时,使用int的最小数填充满
        while (i < k){
            minHeap[i++] = Integer.MIN_VALUE;
        }

        //生成堆
        generaterMinHeap();
     }

     //生成堆
     private void generaterMinHeap() {

         //从最后一个非叶子节点依次往前调整数
         for (int i = k / 2 - 1;i >= 0;i--){
             autoAdjustMinHeap(i,k);
         }
     }

     private void autoAdjustMinHeap(int node, int lenth) {

         int left = node*2 + 1;
         int right = left + 1;

         if (left > lenth - 1){
             return;
         }

         int min = left;
         if (right > lenth - 1){
             min = left;
         }else{
             if (minHeap[min] > minHeap[right]){
                 min = right;
             }
         }

         if (minHeap[min] > minHeap[node]){
             return;
         }

         int t = minHeap[node];
         minHeap[node] = minHeap[min];
         minHeap[min] = t;

         autoAdjustMinHeap(min,lenth);
     }


     public int add(int val) {

         if (val < minHeap[0]){
             return minHeap[0];
         }

         minHeap[0] = val;
         autoAdjustMinHeap(0,k);
         return minHeap[0];

     }
 }


三、使用jJava自带的优先队列

//用Java自带的优先队列实现
  class KthLargest{

      private PriorityQueue<Integer> minHeap;
      private int k;

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

          this.k = k;
          minHeap = new PriorityQueue<Integer>(k);

          for (int i = 0; i < nums.length; i++) {
              add(nums[i]);
          }

      }

      public int add(int val) {

          if (minHeap.size() < k){
              minHeap.offer(val);
          }else if (minHeap.peek() < val){
              minHeap.poll();
              minHeap.offer(val);
          }

          return minHeap.peek();

      }
   
  }

在这里插入图片描述


代码地址:
https://github.com/Han-YLun/LeetCode/blob/master/Practice/src/Que703.java


文章为阿伦原创,如果文章有错的地方欢迎指正,大家互相交流。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值