1. 程式人生 > 其它 >滑動視窗的中位數

滑動視窗的中位數

中位數是有序序列最中間的那個數。如果序列的長度是偶數,則沒有最中間的數;此時中位數是最中間的兩個數的平均數。

例如:

[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.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

class Solution {
    public static double[] medianSlidingWindow(int[] nums, int k) {
        Heap leftHeap = new Heap(nums.length, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o2, o1);
            }
        });

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

        int base = nums[0];

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


        for (int i = 0; i < nums.length; ++i) {
            if (nums[i] <= base) {
                leftHeap.offer(i, nums[i]);
                if (leftHeap.size() > rightHeap.size() + 1) {
                    int[] pop = leftHeap.pop();
                    rightHeap.offer(pop[0], pop[1]);
                }
            } else {
                rightHeap.offer(i, nums[i]);
                if (rightHeap.size() > leftHeap.size()) {
                    int[] pop = rightHeap.pop();
                    leftHeap.offer(pop[0], pop[1]);
                }
            }

            base = leftHeap.peek()[1];

            if (i + 1 >= k) {
                if (k % 2 == 0) {
                    ret[i + 1 - k] = ((long)leftHeap.peek()[1] + rightHeap.peek()[1]) / 2.0;
                } else {
                    ret[i + 1 - k] = leftHeap.peek()[1];
                }
                leftHeap.remove(i + 1 - k);
                rightHeap.remove(i + 1 - k);
            }

        }

        return ret;

    }

    public static void main(String[] args) {
        int[] nums = {1, 3, -1, -3, 5, 3, 6, 7};
        int k = 3;
        double[] ret = medianSlidingWindow(nums, k);
        Arrays.stream(ret).forEach(System.out::println);
    }
}

class Heap {

    private Comparator<Integer> comparator;

    private Map<Integer, Integer> rawIndex2HeapIndexMap;

    private Map<Integer, Integer> heapIndex2RawIndexMap;

    private int size;

    private int[] data;

    public Heap(int limit, Comparator<Integer> comparator) {
        this.size = 0;
        this.data = new int[limit + 1];
        this.comparator = comparator;
        this.rawIndex2HeapIndexMap = new HashMap<>();
        this.heapIndex2RawIndexMap = new HashMap<>();
    }

    private int left(int index) {
        return index << 1;
    }

    private int right(int index) {
        return index << 1 | 1;
    }

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

    private void swap(int a, int b) {
        int rawIndexOfA = heapIndex2RawIndexMap.get(a);
        int rawIndexOfB = heapIndex2RawIndexMap.get(b);

        int tmp = data[a];
        data[a] = data[b];
        data[b] = tmp;

        rawIndex2HeapIndexMap.put(rawIndexOfA, b);
        rawIndex2HeapIndexMap.put(rawIndexOfB, a);
        heapIndex2RawIndexMap.put(a, rawIndexOfB);
        heapIndex2RawIndexMap.put(b, rawIndexOfA);

    }

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

    private void heapifyDown(int index) {
        int left, right;
        while ((left = left(index)) <= size) {
            int bestIndex = index;
            if (comparator.compare(data[left], data[bestIndex]) < 0) {
                bestIndex = left;
            }
            if ((right = right(index)) <= size && comparator.compare(data[right], data[bestIndex]) < 0) {
                bestIndex = right;
            }
            if (bestIndex == index) {
                break;
            }
            swap(bestIndex, index);
            index = bestIndex;
        }
    }

    public int size() {
        return size;
    }

    public void offer(int rawIndex, int ele) {
        size++;
        data[size] = ele;
        rawIndex2HeapIndexMap.put(rawIndex, size);
        heapIndex2RawIndexMap.put(size, rawIndex);
        heapifyUp(size);
    }

    public int[] peek() {
        return new int[]{heapIndex2RawIndexMap.get(1), data[1]};
    }

    public int[] pop() {
        return pop(heapIndex2RawIndexMap.get(1));
    }

    public int[] pop(int rawIndex) {
        int heapIndex = rawIndex2HeapIndexMap.get(rawIndex);

        swap(heapIndex, size);
        int ret = data[size];

        rawIndex2HeapIndexMap.remove(rawIndex);
        heapIndex2RawIndexMap.remove(size);

        size--;

        heapifyUp(heapIndex);
        heapifyDown(heapIndex);

        return new int[]{rawIndex, ret};
    }

    public void remove(int rawIndex) {
        if (rawIndex2HeapIndexMap.containsKey(rawIndex)) {
            pop(rawIndex);
        }
    }
}
心之所向,素履以往 生如逆旅,一葦以航