剑指offer64_滑动窗口的最大值_题解
滑动窗口的最大值
题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
窗口大于数组长度的时候,返回空
分析
方案一:单调队列
维护一个单调队列 \(q\),满足以下两个条件。
- \(q\) 内仅包含窗口内的元素
- \(q\) 内的元素单调递减
则该队列队首元素为窗口的最大元素
算法流程:
- 初始化:单调队列 \(q\),结果数组 \(ret\)
- 将前 \(k\) 个元素添加进队列 \(q\)
- 滑动窗口移动:
- 左边界 \(i-k∈[0,n-k]\) ,右边界 \(i∈[k,n-1]\)
- 在队列 \(q\)中删除左边界元素 \(num[i-k]\)
- 如果队列不为空且队首元素 \(q.front()\) 等于待删除元素 \(nums[i-k]\) ,则队首元素出队
- 在队列 \(q\)中添加右边界元素 \(num[i]\)
- 删除队列中所有小于 \(num[i]\) 的队尾元素,保证队列中所有元素单调递减
- 将队首元素 \(q.front()\) 添加到 \(ret\) 中
- 返回值:返回结果数组 \(ret\)
代码
/*
1.时间复杂度:O(n)
2.空间复杂度:O(k)
k为活动窗口的大小
*/
class Solution
{
public:
class myQueue
{
public:
deque<int> q;
void push(int val)
{
while (!q.empty() && q.back() < val)
{
q.pop_back();
}
q.push_back(val);
}
void pop(int val)
{
if (!q.empty() && q.front() == val)
{
q.pop_front();
}
}
int front()
{
return q.front();
}
};
vector<int> maxInWindows(const vector<int> &num, unsigned int k)
{
vector<int> ret;
if (num.empty() || k < 1 || k > num.size())
return ret;
myQueue q;
for (int i = 0; i < k; i++)
{
q.push(num[i]);
}
ret.push_back(q.front());
for (int i = k; i < num.size(); i++)
{
q.pop(num[i - k]);
q.push(num[i]);
ret.push_back(q.front());
}
return ret;
}
};