【leetcode】239. 滑动窗口最大值
题目内容
思路分析
方法一:优先队列
似乎这种最大值问题比较容易想到优先队列这种数据类型,优先队列可以维护一个最大或最小值,一般是由二叉堆实现的。关于二叉堆我专门写了一篇学习笔记。
优先队列可以自动帮我们得出前i个数的最大值,然而这个题目是个窗口问题,因此每次判断队列的最大值的下标是否在窗口内,若不在则不断弹出最大值直至最大值下标在窗口内,若不在则将其加入答案数组,即可解决窗口带来的难题。
在具体实现时,优先队列中存储的是nums[i]的下标和对应的值。如果只存下标则无法利用优先队列进行排序,若只存对应的值则定位到下标又需要O(n)的时间复杂度。
方法二:单调队列
单调队列也可以维护一个最值。由于我们只需要最大值,遍历数组时,依次从队尾插入元素,若后来来的数字大于等于之前的数字,则证明之前的数字没用了,可以移除掉。这样这个队列就一定变成了队头大于队尾的单调队列,即队头的元素一定是最大的。
|
| |
| | |
| | | |
| | | | |
| | | | |
| | | | | |
数组下标 0 1 2 3 4 5
针对窗口问题,与上一题类似,需要判断队头元素是否在窗口内,若不在则不断弹出队头元素直至队头元素下标在窗口内,若不在则将其加入答案数组。
由于需要在队尾添加删除元素,队头删除元素,因此很自然地采用双向队列来实现单调队列。
在具体实现时,在单调队列中存储数组的下标即可。
代码
#include <vector>
#include <math.h>
#include <limits.h>
#include <queue>
#include <deque>
using namespace std;
// 优先队列法
// 时间复杂度O(nlogn)
// 空间复杂度O(n)
class Solution1 {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
k = min(n, k); // 防止k比n大的情况
priority_queue <pair<int, int>> q;
vector<int> result;
for (int i = 0; i < k; ++i) {
q.emplace(make_pair(nums[i],i));
}
result.push_back(q.top().first);
for (int i = k; i < n; ++i) {
q.emplace(make_pair(nums[i], i));
while ( q.top().second <= i - k ) {
q.pop();
}
result.push_back(q.top().first);
}
return result;
}
};
// 单调队列法
// 时间复杂度O(n),每个元素被放入队列一次,且最多被弹出一次
// 空间复杂度O(k),队列中最多不超过k+1个元素
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
k = min(k, n);
deque<int> dq;
vector<int> result;
for (int i = 0; i < k; ++i) {
while (!dq.empty() && nums[dq.back()] <= nums[i]) {
dq.pop_back(); // 遇到比当前数字大的数字则可以直接移除
}
dq.push_back(i);
}
result.push_back(nums[dq.front()]);
for(int i = k; i < n; ++i) {
while (!dq.empty() && nums[dq.back()] <= nums[i]) {
dq.pop_back(); // 遇到比当前数字大的数字则可以直接移除
}
dq.push_back(i);
while (dq.front() <= i - k) {
dq.pop_front(); // 如果队首数字不在窗口内,则移除
}
result.push_back(nums[dq.front()]);
}
return result;
}
};
int main()
{
Solution s;
vector<int> input{1,3,-1,-3,5,3,6,7};
int k = 3;
vector<int> result;
result = s.maxSlidingWindow(input, k);
int a = 0;
}
收获
- 对优先队列进行了应用
- 学习了单调队列