Day56[26/3/27]T239滑动窗口最大值
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
输入: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 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
示例 2:
输入:nums = [1], k = 1
输出:[1]
提示:
1 <= nums.length <= 105-104 <= nums[i] <= 1041 <= k <= nums.length
解题思路
需要维护一个双端队列,这个双端队列按照元素大小降序排列,且这个队列最长为 k。
然后每次扫描到新的元素的时候,就存入到队列中,并且这个存入是有讲究的,从队列尾部开始找,所有比这个新元素小的元素全部弹出。然后因为这个队列是降序排列的,所以每次取队头就是窗口最大元素了。
但是还需要考虑一个点,就是必须把元素的下标存一下,如果发现队头元素虽然大,但是下标已经过期了(也就是当前的滑动窗口正好滑出了这个下标)那么必须把这个队头元素弹出。
建议配合 B 站视频进行理解。
Code
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
class Solution
{
public:
vector<int> maxSlidingWindow(vector<int> &nums, int k)
{
// 防止尺寸问题
if (nums.size() + 1 - k <= 0)
{
return {};
}
vector<int> res(nums.size() + 1 - k);
deque<pair<int, int>> window;
// 递减队列初始化
for (int i = 0; i < k; i++)
{
while (window.size() && window.back().first < nums[i])
{
window.pop_back();
}
window.push_back({nums[i], i});
}
// 开始找窗口最大
res[0] = window.front().first;
for (int i = 1; i < res.size(); i++)
{
int num = nums[i + k - 1];
// 需要考虑更新问题(下标太旧的需要被抛弃)
if (window.front().second == i - 1)
{
window.pop_front();
}
while (window.size() && window.back().first < num)
{
window.pop_back();
}
window.push_back({num, i + k - 1});
res[i] = window.front().first;
}
return res;
}
};
auto main() -> int
{
cout << "Hello World!" << endl;
}