Sliding Window Median

Question

Question quoted from lintcode
Given an array of n integer, and a moving window(size k), move the window at each iteration from the start of the array, find the median of the element inside the window at each moving. (If there are even numbers in the array, return the N/2-th number after sorting the element in the window. )

Example
For array [1,2,7,8,5], moving window size k = 3. return [2,7,7]

At first the window is at the start of the array like this

[ | 1,2,7 | ,8,5] , return the median 2;

then the window move one step forward.

[1, | 2,7,8 | ,5], return the median 7;

then the window move one step forward again.

[1,2, | 7,8,5 | ], return the median 7;

Idea

Any sorted array can be evenly broken into "left" and "right" chunk, i.e. equal size, and we can keep the median as the last element on the left. If the array cannot be broken evenly, we can make left chunk 1 element more than right chunk.

As we always want to visit the last element from the left chunk, we can use a maximum heap for it.
As we always want to visit the first element from the right chunk, we can use a minimum heap for it.

When the windows slides, remove an element and add another element.

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;

class Element implements Comparable {
    public final int position;
    public final int value;

    Element(int position, int value) {
        this.position = position;
        this.value = value;
    }

    // These two methods were generated by Intellij
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;

        if (o == null || getClass() != o.getClass()) return false;

        Element element = (Element) o;

        if (position != element.position) return false;
        return value == element.value;
    }

    @Override
    public int hashCode() {
        int result = position;
        result = 31 * result + value;
        return result;
    }

    @Override
    public int compareTo(Element o) {
        return this.value - o.value;
    }
}

class Medianer {
    private PriorityQueue left = new PriorityQueue<>(Collections.reverseOrder());
    private PriorityQueue right = new PriorityQueue<>();
    public void slideIn(Element e) {
        if (left.size() == 0 && right.size() == 0){
            left.add(e);
            return;
        }

        Element out = left.size() > right.size()
                ? left.poll()
                : right.poll();

        Element bigger = e;
        Element smaller = out;
        if (out.value > e.value) {
            bigger = out;
            smaller = e;
        }

        left.add(smaller);
        right.add(bigger);
    }
    public void slideOut(Element e) {
        if (left.contains(e)) {
            left.remove(e);
            if (right.size() > 0) {
                left.add(right.poll());
            }
        } else {
            right.remove(e);
            right.add(left.poll());
        }
    }
    public int median() {
        return left.peek().value;
    }
}

public class Solution {
    /*
     * @param nums: A list of integers
     * @param k: An integer
     * @return: The median of the element inside the window at each moving
     */
    public List medianSlidingWindow(int[] nums, int k) {
        Medianer medianer = new Medianer();
        List result = new LinkedList();
        for(int i = 0; i < nums.length; i++) {
            if (i + k - 1 < nums.length) {
                if (i == 0) {
                    for (int j = 0; j < k; j++) {
                        int pos = i + j;
                        medianer.slideIn(new Element(pos, nums[pos]));
                    }
                } else {
                    int outPos = i - 1;
                    int inPos = i + k - 1;
                    medianer.slideOut(new Element(outPos, nums[outPos]));
                    medianer.slideIn(new Element(inPos, nums[inPos]));
                }
                result.add(medianer.median());
            } else {
                break;
            }
        }
        return result;
    }
}

你可能感兴趣的:(Sliding Window Median)