480. 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: 1 ≤ k ≤ input array's size for non-empty array.
学到了两个新的STL函数: C Set 里面的next函数:
if(k % 2) return (double)*next(mst, k/2); else return (double)(*next(mst, k/2 - 1) + *next(mst, k/2)) / 2.0;
Python里面的 insort 将元素插入有序数组。还有一个函数:也是在bisect包下面的bisect_left 该函数用入处理将会插入重复数值的情况,返回将会插入的位置:其目的在于查找该数值将会插入的位置并返回,而不会插入。
def medianSlidingWindow(self, nums, k): from bisect import insort ret = []; tmp = sorted(nums[:k]) def pick(tmp, k): if k % 2: return float( tmp[k/2]) else: return (tmp[k / 2] + tmp[k / 2 - 1]) / 2.0 ret.append(pick(tmp, k)) for i in range(k, len(nums)): tmp.remove(nums[i - k]) insort(tmp, nums[i]) ret.append(pick(tmp, k)) return ret
最后一种解决方案是 一直都想使用的。这种题是很典型的使用multiset来动态维护 k多个元素的。但是这题巧妙在需要用两个 multiset分别维护 两个递增的空间,这样中位数也就是端的元素。
搞了这个以后一个的set应该就是小case了吧!
#define LL long long class Solution { public: vector<double> medianSlidingWindow(vector<int>& nums, int k) { multiset<LL>st1, st2; multiset<LL>::iterator it1, it2; vector<double>ans; /* *将窗口大小k分两半,两个递增区间(k/2个元素) *那么中位数=第一个区间的最大值 or (第一个区间最大值 + 第二个区间的最小值)div 2 */ int m = k/2 + (k%2), len = nums.size(); for(int i = 0; i < len; i ++){ st1.insert(-(nums[i] * (1LL))); if(st1.size() > m){ //st1中元素个数多于规定的m个, 将最大值捣鼓到st2中 it1 = st1.begin(); LL t = *it1; st2.insert(-t);//真实值 st1.erase(it1); } if(st1.size() && st2.size()){//因为删除操作可能导致区间端点出现问题,重新调整使得 st1中的真实最大值 <= st2中的最小值 it1 = st1.begin(); it2 = st2.begin(); LL t1 = *it1; LL t2 = *it2; while(-t1 > t2){ st1.erase(it1); st2.insert(-t1);// st2插入最小值 st2.erase(it2); // st2不再需要次小值 st1.insert(-t2); // st1插入次小值 it1 = st1.begin(); it2 = st2.begin(); t1 = *it1; t2 = *it2; } } if(i >= k - 1){//当压入k个数后,sliding window每移动一次得到一个 中位数 if(k & 1){ ans.push_back(-(*st1.begin())); }else{ ans.push_back((-(*st1.begin()) + *st2.begin()) / 2.0); } it1 = st1.find((-1LL) * (LL)nums[i - k + 1]);//删除第一个 if(it1 != st1.end()){ st1.erase(it1); }else{ st2.erase(st2.find((1LL) * (LL)nums[i - k + 1])); } } } return ans; } };
奥对了特地回来告诉你:这种题一定要注意爆掉int 不怕一万就怕万一 以后切记 用 long long
480. Sliding Window Median