虽然是个做过的题,但是早上心烦意乱,基本还是纯抄leetcode题解。
法一:优先队列
要维护一个滑动窗口内的最大值,可以使用优先队列法,即使用一个最大堆来维护。为了判定当前最大值是否还存在于滑动窗口内,可以同时存储value和index,这样当每次向优先队列加入新元素时,可以将堆顶所有不属于当前窗口的元素都弹出,保证优先队列维持的最大元素是在滑动窗口中的元素。
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
priority_queue<pair<int, int>> q;
for (int i = 0; i < k; ++i) {
q.emplace(nums[i], i);
}
vector<int> ans = {q.top().first};
for (int i = k; i < n; ++i) {
q.emplace(nums[i], i);
while (q.top().second <= i - k) q.pop(); // 如果当前的最大值位于滑动窗口之外,则需要将当前元素弹出
ans.push_back(q.top().first);
}
return ans;
}
};
法二:单调队列
对法一的继续优化。
使用一个队列存储还没有被移除的下标,在队列中,这些下标按照从小到大的顺序存储,并且它们在数组nums中对应的值是严格单调递减的。
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
vector<int> ret;
deque<int> q;
for (int i = 0; i < k; ++i) {
while (!q.empty() && nums[i] >= nums[q.back()]) q.pop_back();
q.push_back(i);
}
ret.push_back(nums[q.front()]);
for (int i = k; i < n; ++i) {
while (!q.empty() && nums[i] >= nums[q.back()]) q.pop_back();
q.push_back(i);
while (q.front() < i - k + 1) q.pop_front();
ret.push_back(nums[q.front()]);
}
return ret;
}
};