[LeetCode] Sliding Window Median

题目

Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.
Examples:
[2,3,4] , the median is 3
[2,3], the median is (2 + 3) / 2 = 2.5
Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Your job is to output the median array for each window in the original array.
For example,
Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.
Window position Median
————— —–
[1 3 -1] -3 5 3 6 7 1
1 [3 -1 -3] 5 3 6 7 -1
1 3 [-1 -3 5] 3 6 7 -1
1 3 -1 [-3 5 3] 6 7 3
1 3 -1 -3 [5 3 6] 7 5
1 3 -1 -3 5 [3 6 7] 6
Therefore, return the median sliding window as [1,-1,-1,3,5,6].

题解

这道题目同样是在数据流中求取中位数,关键在于利用最大堆和最小堆。对于输入的数据保持这样两个堆,一个最大堆maxHeap,一个最小堆minHeap,并有以下性质:1、同时maxHeap中所有的数小于等于minHeap中所有的数(这步操作可以通过先将输入放进minHeap,再从minHeap中取出来最小数放进maxHeap实现) 2、maxHeap中元素个数大于等于minHeap中元素个数,这个性质可以通过插入,删除数据后进行均衡来实现:

public class Solution {
    private Queue<Double> minHeap = new PriorityQueue<>();
    private Queue<Double> maxHeap = new PriorityQueue<>(new Comparator<Double>(){
        @Override
        public int compare(Double o1, Double o2) {
            if (o1 > o2) return -1;
            else if (o1 < o2) return 1;
            else return 0;
        }
    });
    public double[] medianSlidingWindow(int[] nums, int k) {
        int n = nums.length - k + 1;
        if (n <= 0) return new double[0];
        double[] result = new double[n];

        for (int i = 0; i <= nums.length; i++) {
            if (i >= k) {
                result[i - k] = getM();
                remove(nums[i - k]);
            }
            if (i < nums.length)
                add(nums[i]);
        }
        return result;
    }
    private void add(int num){
        //保持最大堆中元素小于最小堆中元素
        minHeap.add((double)num);
        maxHeap.add(minHeap.poll());
        //元素数目均衡操作
        if (minHeap.size() > maxHeap.size()) maxHeap.add(minHeap.poll());
        if (maxHeap.size() - minHeap.size() > 1) minHeap.add(maxHeap.poll());
    }

    private void remove(int num){
        double mid = getM();
        double n = (double) num;
        if (n <= mid) {
            maxHeap.remove(n);
        } else {
            minHeap.remove(n);
        }
        if (maxHeap.size() < minHeap.size()) maxHeap.add(minHeap.poll());
        if (maxHeap.size() - minHeap.size() > 1) minHeap.add(maxHeap.poll());
    }

    private double getM() {
        if (maxHeap.isEmpty() && minHeap.isEmpty()) return 0;
        if (minHeap.size() == maxHeap.size()) return ((double)maxHeap.peek() + (double)minHeap.peek()) / 2.0;
        else return (double)maxHeap.peek();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值