堆在数据流的应用

LeetCode295数据流的中位数

思路:

  • 查询流的中位数,不可以每次都在查询时排序,因为流是一直变化的,每次都要排序性能很低
  • 可以使用两个堆,一个大顶堆来存储较小的数,一个小顶堆来存储较大的数
  • 大顶堆 小顶堆
  • 1 2 3 -- 7 8 9
  • 大顶堆的最大值和小顶堆的最小值在一起,两个堆数量相等时 -> 中位数就是两堆堆顶的中位数,数量不相等时,中位数就是数量较多的堆的堆顶

如何确保两堆元素平衡

  • 两边元素数相同时,向左边添加一个元素
  • 元素数不相同时,向右边添加一个元素
  • 在添加元素时,不可以随意加入元素,会造成两堆的大小没有保持一堆大,一堆小
  • 左边添加一个元素后,为维持左堆的较小性,将左边堆顶->最大数移动到右堆
  • 右边添加一个元素后,为维持右堆的较大性,将右边堆堆顶->最小数移到左堆

中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。

  • 例如 arr = [2,3,4] 的中位数是 3
  • 例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5

实现 MedianFinder 类:

  • MedianFinder() 初始化 MedianFinder 对象。
  • void addNum(int num) 将数据流中的整数 num 添加到数据结构中。
  • double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10-5 以内的答案将被接受。

示例 1:

输入
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
输出
[null, null, null, 1.5, null, 2.0]

解释
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1);    // arr = [1]
medianFinder.addNum(2);    // arr = [1, 2]
medianFinder.findMedian(); // 返回 1.5 ((1 + 2) / 2)
medianFinder.addNum(3);    // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0

提示:

  • -105 <= num <= 105
  • 在调用 findMedian 之前,数据结构中至少有一个元素
  • 最多 5 * 104 次调用 addNumfindMedian
class MedianFinder {
    PriorityQueue<Integer> bigHeap; // 大顶堆记录较小值
    PriorityQueue<Integer> smallHeap;// 小顶堆记录较大值

    
    public MedianFinder() {
        
    Comparator<Integer> comparator=new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2-o1;
        }
    };
         bigHeap=new PriorityQueue<>(comparator);
         smallHeap=new PriorityQueue<Integer>();
         
    }
    

    // 1 
    // 2 3 4 5 6 
    public void addNum(int num) {
        // 两边个数一样时,左边添加一个元素
        // 两边个数不一样时,右边添加一个元素
        
        // 左边添加元素时,将右边顶部元素加入
        // 右边添加元素时,将左边顶部元素加入
        int leftSize=bigHeap.size();
        int rightSize=smallHeap.size();
        if (leftSize==rightSize) {
             bigHeap.offer(num);
             smallHeap.offer(bigHeap.poll());
            
        }else {
             smallHeap.offer(num);
             bigHeap.offer(smallHeap.poll());
        }

    }
    
    public double findMedian() {
        if (bigHeap.size()==smallHeap.size()) {
            return (bigHeap.peek()+smallHeap.peek())/2.0;
        }else if(bigHeap.size()<smallHeap.size()) {
                return smallHeap.peek()/1.0;
        }else{
            return bigHeap.peek()/1.0;
        }
    }

}

LeetCode215数组中的第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

思路:

  • 使用小顶堆,先加入k个元素到堆里
  • 遍历第k后的元素,如果大于堆顶,删除堆顶的元素,将其加入堆,会重新建堆
  • 遍历结束后,由于堆里只有k个元素,则小顶堆 堆顶就是第k个最大的元素
  • 堆里其它元素比它大
  • 没有进入堆的元素都小于堆内的元素
class Solution {
    public int findKthLargest(int[] nums, int k) {
    PriorityQueue<Integer> heap=new PriorityQueue();// 默认小顶堆
      for (int i = 0; i <k; i++) {
            heap.offer(nums[i]);
      }
      for (int i = k; i < nums.length; i++) {
        if (nums[i]>heap.peek()) {
            heap.poll();
            heap.offer(nums[i]);
        }
    }
    return heap.peek();

    }
}
class KthLargest {
     PriorityQueue<Integer> heap ;
     int size;
    public KthLargest(int k, int[] nums) {
        this.size = k;
        heap = new PriorityQueue<Integer>(k);
        for(int i: nums) {
            add(i);
        }
    }
    
    public int add(int val) {
        if(heap.size() < size) {
            heap.offer(val);
        }
        else if(heap.peek() < val) {
            heap.poll();
            heap.offer(val);
        }
        return heap.peek();
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值