leetcode480. Sliding Window Median
问题描述:
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:
You may assume k
is always valid, ie: k
is always smaller than input array's size for non-empty array.
解题思路:
这道题目给我们一个滑动窗口,让我们寻找窗口中数字的中位数,而窗口中的数字是无序的。
如果我们想要中位数,我们应该将数字们放入一个容器并使之有序。
最简单的思路就是,将数字们放进vector中然后使用sort进行排序然后找到中位数:这样的时间复杂度为 n*klogk
看了大神的解法,大神用的是multiset这一容器
首先将k个数字放进容器中,并且使用迭代器iterator来寻找中位数可能出现的点:k/2。
若k为偶数,则应该为 k/2 位置与 k/2 -1 位置中的数字的均值
若k为奇数,则为 k/2
这里他用了一个很好的方式来判断:
*mid + *prev(mid, 1 - k%2)) / 2.0f
然后我们再向容器中加入下一个数字,这里用的中位数的定义:中间的值。
我们可以通过判断加入(离开)的数字与当前中位数的关系来判断中位数是否需要移动。
当nums[i]加入以及nums[i-k]的时候:以奇数为例 k = 3 [小于中位数的数字的个数, 中, 大于中位数数字的个数]
1. nums[i] < *mid(注意这里是当前的中位数!):中位数会被拉低 [2, 1, 1] -> [1, 1, 2]
nums[i-k] <= *mid: 中位数应当升高 : [1, 1, 2]->[0, 1, 2]->[1, 1, 1]
2. nums[i] < *mid: 中位数被拉低 [2,1,1]->[1,1,2]
nums[i-k] > *mid: [1, 1, 2] -> [1, 1, 1]
3. nums[i] >= *mid: [1, 1, 2]
nums[i-k] <= *mid: [1, 1, 2]->[2,1,1]->[1,1,1]
4. nums[i] >= *mid: [1, 1, 2]
nums[i-k] > *mid: [1, 1, 2] -> [1, 1, 1]
代码:
class Solution { public: vector<double> medianSlidingWindow(vector<int>& nums, int k) { vector<double> ret; multiset<double> ms(nums.begin(), nums.begin()+k); auto mid = next(ms.begin(), k/2); for(int i = k; i < nums.size() ; i++){ ret.push_back((*mid + *prev(mid, 1 - k%2)) / 2.0f); ms.insert(nums[i]); if(nums[i] < *mid) mid--; if(nums[i-k] <= *mid) mid++; ms.erase(ms.lower_bound(nums[i-k])); } ret.push_back((*mid + *prev(mid, 1 - k%2)) / 2.0f); return ret; } };
c++学习:
这道题目里我们使用到了
1. multiset,multiset 与 set有不同之处: multiset中元素可以重复,但是set中不能
2. STL中的Iterator: c++ iterator分类及使用