-
题目:剑指Offer59-Ⅰ.滑动窗口的最大值
输入一个数组nums和一个int k,k表示窗口大小;
返回一个数组,表示nums从左往右的所有大小为k的窗口中的最大值;
在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小; -
思路:
若nums长为n,[ 0,k-1 ] 是第一个窗口,[ n - k, n - 1 ]是最后一个窗口,对于每个窗口都要求最大值;
首先只能遍历窗口的起始位置O(n);
对于每一个长为k的窗口,要想求最大值:① 暴力遍历当前窗口的所有值,需要O(k)时间 ②如何随着窗口的右移,O(1)求出窗口最大值
1.维护一个单调不严格递减队列deque:O(n):遍历起始位置O(n),对于每个窗口只需O(1)获得最大值,空间O(k):deque最多存当前窗口内的所有元素(当当前窗口内元素不严格单减的时候)
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
if (!n || k > n) return {
};
vector<int> res;//存每个窗口的最大值
deque<int> dq;//单调递减队列
for (int i = 0; i < k; ++i) {
//先把第一个窗口放进去,即以下标0起始的长为k的窗口
while (!dq.empty() && dq.back() < nums[i]) dq.pop_back();//重复元素留着
dq.push_back(nums[i]);
}
res.push_back(dq.front());//第一个窗口的最大值
for (int i = 1; i <= n - k; ++i) {
//枚举下标1,2,。。。,n-k为窗口的起始点,并求最大值
if (nums[i - 1] == dq.front()) dq.pop_front();//窗口右移一步时,最左边少了一个,最右边多了一个
//维护deque单调递减的性质,把右边新加入窗口的元素放在合适位置,并时刻保持队首为最大值
while (!dq.empty() && dq.back() < nums[i + k - 1]) dq.pop_back();//这里<而不是<=,意思是重复元素留着,防止如果重复元素为最大值,若刚好退出窗口,pop_front后还留着一个
dq.push_back(nums[i + k - 1]);
res.push_back(dq.front());//队首为当前窗口最大值
}
return res;
}
};
- 总结:
题解大佬说单调队列的通用写法是存索引,还不会用。。