leetcode 链接:剑指 Offer 59 - I. 滑动窗口的最大值
题目
给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。
提示:
你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。
示例:
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3输出: [3,3,5,5,6,7]解释:滑动窗口的位置 最大值--------------- -----[1 3 -1] -3 5 3 6 7 31 [3 -1 -3] 5 3 6 7 31 3 [-1 -3 5] 3 6 7 51 3 -1 [-3 5 3] 6 7 51 3 -1 -3 [5 3 6] 7 61 3 -1 -3 5 [3 6 7] 7
解答 & 代码
单调队列(用双端队列实现)
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int size = nums.size();
vector<int> result; // 结果数组,存储每个滑动窗口的最大值
if(size == 0 || k <= 0)
return result;
// 单调队列(用双端队列实现),存储的是元素下标
// 队列中从头到尾存储的下标对应的元素值递减,因此队首是最大值的下标
deque<int> q;
// 先将前 k 个元素的下标存入队列
for(int i = 0; i < k; ++i)
{
// 如果队尾存的下标对应的值小于等于当前元素,则不断弹出队尾
// 直到队列为空或队尾存的下标对应的值大于当前元素
while(!q.empty() && nums[i] >= nums[q.back()])
q.pop_back();
// 将当前元素的下标存入队尾
q.push_back(i);
}
// 将第一个滑动窗口(即前k个元素)的最大值(即队首存的下标对应的值)存入结果数组
result.push_back(nums[q.front()]);
// 滑动窗口
for(int i = k; i < size; ++i)
{
// 将滑动窗口新的的右边界下标存入单调队列:
// 如果队尾存的下标对应的值小于等于右边界元素,则不断弹出队尾
// 直到队列为空或队尾存的下标对应的值大于右边界元素
while(!q.empty() && nums[i] >= nums[q.back()])
q.pop_back();
// 将右边界下标存入队列
q.push_back(i);
// 如果队首存的下标小于窗口的左边界,则不断弹出队首
// 直到队首存的下标在窗口范围内
while(!q.empty() && q.front() < i - k + 1)
q.pop_front();
// 队首存的下标对应的元素就是当前窗口的最大值,存入结果数组
result.push_back(nums[q.front()]);
}
return result;
}
};
执行结果:
执行结果:通过
执行用时:16 ms, 在所有 C++ 提交中击败了 92.76% 的用户
内存消耗:15.5 MB, 在所有 C++ 提交中击败了 66.49% 的用户
