题目239 滑动窗口最大值
11.1 官方解析
方法一:优先队列
方法二:单调队列
方法三:分块 + 预处理
11.2 解法1
(看到这道题时首先想到的就是暴力解法,但是经过测试,会超出时间限制!因此不可取,下面是 X暴力解法X )
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> result;
for (int i = 0; i < nums.size() - k + 1; ++i) {
int max_num = INT_MIN;
for (int j = i; j < i + k; ++j) {
max_num = max(max_num, nums[j]);
}
result.push_back(max_num);
}
return result;
}
};
解法2
采用双端队列的方法:
维护一个双端队列当作滑动窗口。每次向右移动时,把窗口左端的值从队列左端剔除,把队列右边小于窗口右端的值剔除(即双端队列中的元素 ≤ k )。这样做的结果就是:双端队列的最左端永远都是当前窗口内的最大值!
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if (k == 0) {
return {};
}
deque<size_t> window; // 双端队列里面存储元素下标
vector<int> result;
// 初始的滑动窗口
for (size_t i = 0; i < k; ++i) {
// 在滑动窗口不为空的条件下,只要准备新进来的元素大于滑动窗口最后一个元素,
// 就将最后一个元素剔除!直到该队列的末尾比新数大或者队列为空的时候才停止
while (!window.empty() && nums[window.back()] < nums[i]) {
window.pop_back();
}
window.push_back(i);
}
result.push_back(nums[window.front()]);
for (size_t i = k; i < nums.size(); ++i) {
// 判断是否需要移动窗口
if (!window.empty() && window.front() + k <= i) {
window.pop_front();
}
while (!window.empty() && nums[window.back()] < nums[i]) {
window.pop_back();
}
window.push_back(i);
result.push_back(nums[window.front()]);
}
return result;
}
};