题意
给你一个数组 nums,有一个长度为 k 的窗口从最左端滑动到最右端。窗口中有 k 个数,每次窗口向右移动 1 位。你的任务是找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。$(n, k \in [1, 100000])$
Solution
用优先队列+延迟删除有点麻烦,可以考虑直接用 multiset 做,本质都是一样的,维护两个大小相同或差一的集合(自动排序)$l 和 r$,$l$ 维护小于等于中位数的值,$r$ 维护大于等于中位数的值,$multiset$ 的优秀特性可以在 $log$ 时间复杂度内进行增删操作。具体细节较多,时间复杂度 $O(nlog(k))$。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class Solution { public: vector<double> medianSlidingWindow(vector<int>& a, int k) { multiset<double> l, r; int n = a.size(); vector<double> res; for (int i = 0; i < n; i++) { if (i >= k) { if (l.count(a[i - k])) l.erase(l.find(a[i - k])); else r.erase(r.find(a[i - k])); } l.insert((double)a[i]); while (l.size() && r.size() && *(--l.end()) > *r.begin()) { l.insert(*r.begin()); r.insert(*(--l.end())); l.erase(*(--l.end())); r.erase(*r.begin()); } while (l.size() - 1 > r.size()) { r.insert(*(--l.end())); l.erase(--l.end()); } if (i >= k - 1) { if (k & 1) res.push_back(*(--l.end())); else res.push_back((*(--l.end()) + *r.begin()) / 2.0); } } return res; } };
|