480. 滑动窗口中位数

中位数是有序序列最中间的那个数。如果序列的长度是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。

例如:

[2,3,4],中位数是 3
[2,3],中位数是 (2 + 3) / 2 = 2.5
给你一个数组 nums,有一个长度为 k 的窗口从最左端滑动到最右端。窗口中有 k 个数,每次窗口向右移动 1 位。你的任务是找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sliding-window-median
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

import java.util.*;

class Solution {
    public double[] medianSlidingWindow(int[] nums, int k) {

        Heap leftHeap = new Heap(nums, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o2, o1);
            }
        });

        Heap rightHeap = new Heap(nums, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        });

        double[] ans = new double[nums.length - k + 1];

        for (int i = 0; i < nums.length; ++i) {
            if (leftHeap.empty() || nums[i] <= nums[leftHeap.peek()]) {
                leftHeap.push(i);
            } else {
                rightHeap.push(i);
            }

            while (leftHeap.size() < rightHeap.size()) {
                leftHeap.push(rightHeap.pop());
            }

            while (rightHeap.size() + 1 < leftHeap.size()) {
                rightHeap.push(leftHeap.pop());
            }

            if (i >= k - 1) {
                int length = (leftHeap.size() + rightHeap.size());
                if (length % 2 == 1) {
                    ans[i - (k - 1)] = nums[leftHeap.peek()];
                } else {
                    ans[i - (k - 1)] = (1D * nums[leftHeap.peek()] + nums[rightHeap.peek()]) / 2.0;
                }
                leftHeap.delete(i - (k - 1));
                rightHeap.delete(i - (k - 1));
            }
        }
        return ans;
    }
}

class Heap {
    private int[] original;

    private Comparator<Integer> comparator;

    private List<Integer> data;

    private Map<Integer, Integer> indexMap;

    private int size = 0;

    public Heap(int[] original, Comparator<Integer> comparator) {
        this.original = original;
        this.comparator = comparator;
        this.data = new ArrayList<>();
        this.indexMap = new HashMap<>();
    }

    private int parent(int index) {
        return (index - 1) >> 1;
    }

    private int left(int index) {
        return index * 2 + 1;
    }

    private int right(int index) {
        return index * 2 + 2;
    }

    private int originalData(int index) {
        return original[data.get(index)];
    }

    private void heapifyUp(int index) {
        while (index != 0) {
            int parent = parent(index);
            if (comparator.compare(originalData(index), originalData(parent)) < 0) {
                swap(index, parent);
                index = parent;
            } else {
                break;
            }
        }
    }

    private void heapifyDown(int index) {
        int left, right;
        while ((left = left(index)) < this.size) {
            int goal = index;
            if (comparator.compare(originalData(index), originalData(left)) > 0) {
                goal = left;
            }
            if ((right = right(index)) < this.size && comparator.compare(originalData(goal), originalData(right)) > 0) {
                goal = right;
            }
            if (goal == index) {
                break;
            }
            swap(goal, index);
            index = goal;
        }
    }

    public void push(int x) {
        if (data.size() > this.size) {
            data.set(this.size, x);
        } else {
            data.add(x);
        }
        indexMap.put(x, this.size);
        heapifyUp(this.size++);
    }

    private void swap(int idx1, int idx2) {
        int x1 = data.get(idx1);
        int x2 = data.get(idx2);
        data.set(idx1, x2);
        data.set(idx2, x1);
        indexMap.put(x1, idx2);
        indexMap.put(x2, idx1);
    }

    public void delete(int x) {
        if (!indexMap.containsKey(x)) {
            return;
        }
        Integer index = indexMap.get(x);
        swap(index, --this.size);
        indexMap.remove(x);
        heapifyUp(index);
        heapifyDown(index);
    }

    public int peek() {
        return data.get(0);
    }

    public int pop() {
        int ans = data.get(0);
        swap(0, --size);
        indexMap.remove(ans);
        heapifyDown(0);
        return ans;
    }

    public int size() {
        return size;
    }

    public boolean empty() {
        return this.size == 0;
    }
}
上一篇:EMC CX4-480更换控制器


下一篇:480. 滑动窗口中位数