滑动窗口的中位数 · Sliding Window Median

[抄题]:node

给定一个包含 n 个整数的数组,和一个大小为 k 的滑动窗口,从左到右在数组中滑动这个窗口,找到数组中每一个窗口内的中位数。(若是数组个数是偶数,则在该窗口排序数字后,返回第 N/2 个数字。)算法

对于数组 [1,2,7,8,5], 滑动大小 k = 3 的窗口时,返回 [2,7,7]数组

最初,窗口的数组是这样的:数据结构

[ | 1,2,7 | ,8,5] , 返回中位数 2;ide

接着,窗口继续向前滑动一次。函数

[1, | 2,7,8 | ,5], 返回中位数 7;this

接着,窗口继续向前滑动一次。spa

[1,2, | 7,8,5 | ], 返回中位数 7;debug

 [暴力解法]:rest

时间分析:

空间分析:

[思惟问题]:

  1. 不理解两个heap和窗口的大小关系:把窗口容量全扔进来,具体分到哪一个格子另当别论
  2. 体会到了treemap相对于heap的优越性:想romove哪一个点是随便的。注意接口、实现都不是PQ,是treeset 并且树状的题想一想里面装的是node仍是数字

[一句话思路]:

窗口移动就是加一个元素、减一个元素,用俩函数实现,因此能够放在maxheap minheap中

[输入量]:空: 正常状况:特大:特小:程序里处理到的特殊状况:异常状况(不合法不合理的输入):

[画图]:

[一刷]:

  1. 窗口满了以后romove第一个点,i - k + 1,不是第i个点,写习惯了就错了。重要的参数要提早注释行
  2. 要在maxheap有点的前提下进行节点交换,想到其临界状况:还没有点

[二刷]:

[三刷]:

[四刷]:

[五刷]:

  [五分钟肉眼debug的结果]:

[总结]:

参数须要边分析边写,留意leetcode lintcode接口是否是不同

[复杂度]:Time complexity: O(n个数*左右treeset体积lgk) Space complexity: O(n)

[英文数据结构或算法,为何不用别的数据结构或算法]:

  1. node中本身的类、本身的compareTo方法都应该有参数,不然没法调用,要理解其做用
  2. 只有implements能实现接口,仍是不少个。不要写extends

[关键模板化代码]:

  自制Collections.sort 方法有一个字母 第一位不相等
  自制compareTo 方法有两个字母 第二位相等

[其余解法]:

[Follow Up]:

[LC给出的题目变变变]:

class Node implements Comparable<Node>{ int id; int val; Node (int id, int val){ this.id = id; this.val = val; } public int compareTo(Node other) { Node a = other; if (this.val == a.val) { return this.id - a.id; }else { return this.val - a.val; } } } 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 double[] medianSlidingWindow(int[] nums, int k) { //corner case
        int n = nums.length; double[] result = new double[n]; if (nums == null || k == 0) { return result; } TreeSet<Node> minHeap = new TreeSet<>(); TreeSet<Node> maxHeap = new TreeSet<>(); //add all nums into window, rest
        int half = (k + 1) / 2; int index = 0; for (int i = 0; i < k - 1; i++) { add(minHeap, maxHeap, half, new Node(i, nums[i])); } for (int i = k - 1; i < n; i++) { add(minHeap, maxHeap, half, new Node(i, nums[i])); nums[index] = minHeap.last().val; index++; remove(minHeap, maxHeap, new Node(i - k + 1, nums[i - k + 1])); } return result; } // write reference first!
    void add(TreeSet<Node> minHeap, TreeSet<Node> maxHeap, int size, Node node) { if (minHeap.size() < size) { minHeap.add(node); }else { maxHeap.add(node); } if (minHeap.size() == size) { //don't forget just minheap, need to ensure
            if (maxHeap.size() > 0 && minHeap.last().val > maxHeap.first().val) { Node b = minHeap.last(); Node s = maxHeap.first(); minHeap.remove(b); minHeap.add(s); maxHeap.remove(s); maxHeap.add(b); } } } void remove(TreeSet<Node> minHeap, TreeSet<Node> maxHeap, Node node) { if (minHeap.contains(node)) { minHeap.remove(node); }else { maxHeap.remove(node); } } }
View Code

 

 [代码风格] :

  1. 打草稿的时候先把函数参数写了 是分析出来的,不要主函数调用的时候就瞎写
  2. Node 注意开头得大写
相关文章
相关标签/搜索