480. Sliding Window Median

480. Sliding Window Median

  • 方法1: multiset (priority_queue)
    • Complexity
  • 方法2: insertion sort

Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.

Examples:

[2,3,4] , the median is 3

[2,3], the median is (2 + 3) / 2 = 2.5

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Your job is to output the median array for each window in the original array.

For example,

Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.

Window position                Median
---------------               -----
[1  3  -1] -3  5  3  6  7       1
 1 [3  -1  -3] 5  3  6  7       -1
 1  3 [-1  -3  5] 3  6  7       -1
 1  3  -1 [-3  5  3] 6  7       3
 1  3  -1  -3 [5  3  6] 7       5
 1  3  -1  -3  5 [3  6  7]      6
Therefore, return the median sliding window as [1,-1,-1,3,5,6].

Note:

  1. You may assume k is always valid, ie: k is always smaller than input array’s size for non-empty array.

花花:https://zxi.mytechroad.com/blog/difficulty/hard/leetcode-480-sliding-window-median/
480. Sliding Window Median_第1张图片
480. Sliding Window Median_第2张图片
480. Sliding Window Median_第3张图片

方法1: multiset (priority_queue)

grandyang: http://www.cnblogs.com/grandyang/p/6620334.html
discussion: https://leetcode.com/problems/sliding-window-median/discuss/96340/O(n-log-k)-C%2B%2B-using-multiset-and-updating-middle-iterator

思路:

multiset是不支持直接O(1)提取中位数的。那么解决的办法就是maintain一个pointer,每次插入删除时和当前的median做对比,如果插入的是左边,median一定会被拉低,如果是右边,median被拉高。相应调整median iterator的位置。而对于滑出了窗口的数,我们要用erase删除,但是必须用lower_bound来定位这个元素,因为multiset里面可能会存在重复的该元素,不能一次都删掉。lower_bound会指向multiset中第一个大于等于目标值的数字。

Complexity

Time complexity: O(n log k)
Space complexity: O(logk)

class Solution {
public:
    vector<double> medianSlidingWindow(vector<int>& nums, int k) {
        vector<double> result;
        // initialize the window
        multiset<int> window(nums.begin(), nums.begin() + k);
        // iterator to the median
        auto mid = next(window.begin(), k / 2); //偶数情况下取的是右中位
        for (int i = k; ; i++) {
            
            result.push_back(((double)(*mid) + *prev(mid, (1 - k % 2)) )* 0.5);
            // if hit the end, return
            if (i == nums.size()) return result;
           
            // insert
            window.insert(nums[i]);
            
            // 如果要被插入左半 mid--
            if (nums[i] < *mid) {
                mid--;
            }
            // 如果要被删除的在左半mid++
            if (nums[i - k] <= *mid) {
                mid++;
            }
            // 考虑几种情况:
            // 1. 插左删左,插右删右,mid不变
            // 2. 插左删右,mid--
            // 3. 插右删左,mid++
            window.erase(window.lower_bound(nums[i - k]));
            
        }
    }
};

方法2: insertion sort

huahua: https://zxi.mytechroad.com/blog/difficulty/hard/leetcode-480-sliding-window-median/

// Author: Huahua
// Running time: 99 ms
class Solution {
public:
  vector<double> medianSlidingWindow(vector<int>& nums, int k) {    
    vector<double> ans;
    if (k == 0) return ans;
    vector<int> window(nums.begin(), nums.begin() + k - 1);
    std::sort(window.begin(), window.end());
    for (int i = k - 1; i < nums.size(); ++i) {
      window.push_back(nums[i]);
      auto it = prev(window.end(), 1);
      auto const insertion_point = 
              std::upper_bound(window.begin(), it, *it);      
      std::rotate(insertion_point, it, it + 1);          
      ans.push_back((static_cast<double>(window[k / 2]) + window[(k - 1) / 2]) / 2);
      window.erase(std::find(window.begin(), window.end(), nums[i - k + 1]));      
    }
    return ans;
  }
};

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