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:
花花:https://zxi.mytechroad.com/blog/difficulty/hard/leetcode-480-sliding-window-median/
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中第一个大于等于目标值的数字。
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]));
}
}
};
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;
}
};