一、介绍
1.题目描述
题目链接:https://leetcode-cn.com/problems/sliding-window-maximum/
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
- 返回滑动窗口中的最大值。
注意事项:
- 如果 k = 1,可以直接返回
2.测试样例
[1,3,-1,-3,5,3,6,7]
3
# [3,3,5,5,6,7]
[1]
1
# [1]
[1,-1]
1
# [1,-1]
[9,11]
2
# [11]
[4,-2]
2
# [4]
[7,2,4]
2
# [7,4]
二、题解
1、优先队列🔴
- 创建一个优先队列(大顶堆),记录数值和对应下标。
- 先对第一个窗口中的内容进行处理,加入队列中,往 ans 中加入第一个最大元素。
- 对于接下来的窗口内容,依次插入,判断当前最大值是否在窗口中
- 如果在窗口中,加入到答案
- 如果不在,删除该堆顶
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if(k==1) return nums;
int n=nums.size();
// q 为优先队列,ans 记录答案数组
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;
}
};

2、双端单调队列🟢
- 创建一个双端队列,遍历插入当前数的下标,为保证递增:
- 若当前数比较大,弹出队列中所有小于当前数的下标
- 否则直接插入
- 第一个窗口遍历完,队列头就是第一个答案
- 遍历之后窗口时
- 若队列头下标不在窗口内,则弹出队头
- 若当前数比较大,弹出队列中所有小于当前数的下标
- 否则直接插入
- 最后剩下的队列头就是当前窗口的最大值下标
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if(k==1) return nums;
int n=nums.size();
// 双端队列
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);
}
// ans 记录答案
vector<int> ans={nums[q.front()]};
// 处理接下来的窗口
for(int i=k;i<n;i++){
// 下标超出窗口,弹出
while(q.front()<=i-k) q.pop_front();
// 如果队列内的数小于当前数,弹出
while(!q.empty()&&nums[i]>=nums[q.back()]){
q.pop_back();
}
q.push_back(i);
// 当前队列头为当前窗口内最大值下标
ans.push_back(nums[q.front()]);
}
return ans;
}
};

这篇博客介绍了如何利用优先队列(大顶堆)和双端队列(deque)来解决LeetCode上的滑动窗口最大值问题。两种方法分别通过维护一个包含窗口内元素及其下标的队列,动态更新最大值。在滑动窗口移动时,队列不断调整以保持窗口内的最大值。这两个高效的数据结构解决方案能帮助我们在线性时间内找到每个窗口的最大值。
802

被折叠的 条评论
为什么被折叠?



