滑動窗口的中位數 · 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 注意開頭得大寫
相關文章
相關標籤/搜索