480. 滑动窗口中位数 ( 风险对冲-大顶堆小顶堆-滑动窗口 )

LeetCode:480. 滑动窗口中位数

在这里插入图片描述

滑动窗口

难点: 在窗口右移的同时, 还要考虑窗口中的顺序问题, 快速定位到中位数

《风 险 对 冲》:双堆对顶,大堆小堆同时维护

在这里插入图片描述

思路:

  1. 大小顶堆一定思考清楚了。 小顶堆放大数据,大顶堆放小数据,这样才会导致中间的数据在顶堆的最上方,取数据容易
  2. 一定维持小顶堆的数据长度跟大顶堆的相同(偶数的时候)或者是比大顶堆大一(基数的时候)。这样在获取数据的时候才能够非常容易的知道应该取哪个位置的数据。


AC Code

class Solution {

    // 从小到大
    PriorityQueue<Integer> small = new PriorityQueue<>();
    // 从大到小
    PriorityQueue<Integer> big = new PriorityQueue<>(Comparator.reverseOrder());
    public double[] medianSlidingWindow(int[] nums, int k) {
        
        // 风险对冲
        int len = nums.length;
        // 初始化
        for(int i = 0; i < k; i++) small.add(nums[i]);        
        for(int i = 0; i < k / 2; i++) big.add(small.poll());

        int left = 0, right = k, idx = 0;
        double[] ans = new double[len - k + 1];

        while(right <= len) {
            double mid = getMid(k);
            ans[idx++] = mid;
            if(right == len) break;

            // 更新区间
            // 减 left , 增 right
            int rm = nums[left++], ad = nums[right++];
            if(small.contains(rm)) small.remove(rm);
            // 在 big 中
            else big.remove(rm);
            // 可要可不要
            //rb();
            // add
            small.add(ad);
            rb();
        }

        return ans;
    }

    public double getMid(int k){
        // 偶数
        // 这里必须是在里面就强转成 double 了, 不然会超数据范围  [2147483647,2147483647]
        if(k % 2 == 0) return ((double)small.peek() + (double)big.peek()) / 2.0;
        // 奇数
        else return small.peek();
    }


    public void rb(){
        if(small.size() > 0 && big.size() > 0 && big.peek() > small.peek()) {
            int tmp = small.peek();
            big.add(tmp);
            small.remove(tmp);
        }

        if(small.size() - big.size() > 1) {
            int tmp = small.peek();
            big.add(tmp);
            small.remove(tmp);
        }

        if(big.size() - small.size() > 0) {
            int tmp = big.peek();
            small.add(tmp);
            big.remove(tmp);
        }
    }

}





参考: 《风 险 对 冲》:双堆对顶,大堆小堆同时维护,44ms


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值