[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 minHeap = new PriorityQueue<>();
    private Queue maxHeap = new PriorityQueue<>(new Comparator(){
        @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();
    }
}

你可能感兴趣的:(算法和数据结构)