题目:
一个整型数组num 窗口大小w 从左到右滑动窗口。
窗口滑动过程中每次都会产生一个最大值。【总共产生n - w + 1个窗口】
思路:
常规解法:O(n*w)的解法复杂度太高。
本题解法复杂度:O(n) 大致思想如下:
维护一个双端队列dq 记录遍历的元素下标。 记:num[i]为当前遍历到的元素 dq队尾元素为j。
若 num[i] < num[j] 将i放入队尾 结束。【说明当前元素并没有更新记录的最大值下标】
若 num[i] >= num[j] 将j从队首弹出 继续比较。【说明当前元素的加入会更新最大值 此时需要多步操作更新最大值】
注意:如果队首元素为i-w 那么此时需要将队首从队列弹出,因为此时记录的最大值下标已经不是当前w大小窗口的最大值。
贴代码:
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
void getWindowMax(vector<int> num, int w, vector<int> &maxNum)
{
if (num.empty() || w < 1 || num.size() < w)
{
return;
}
// 定义一个双端队列 保存数组元素下标
deque<int> dq; // 插入数据在队尾操作 弹出数据在队首操作
maxNum.resize(num.size() - w + 1, 0);
int idx = 0;
// 遍历给定数组num 找出w窗口内的最大值 放入maxNum数组中
for (int i = 0; i < num.size(); ++i)
{
// 队列非空 且当前队尾元素 < 当前数组元素
// => 弹出队尾
while(!dq.empty() && num[dq.back()] <= num[i])
{
dq.pop_back();
}
// 当前队尾元素 < 当前数组元素 => 将当前元素下标放入队尾
dq.push_back(i);
// 下标过期 从队首弹出即可
if (dq.front() == i - w)
{
dq.pop_front();
}
if (i >= w - 1)
{
maxNum[idx++] = num[dq.front()];
}
}
}
int main(void)
{
int a[] = {1, 3, 5, 5, 2, 6, 4};
int w = 3;
vector<int> num(a, a + 7);
vector<int> res;
getWindowMax(num, w, res);
if (res.empty() == false)
{
vector<int>::iterator it;
for (it = res.begin(); it != res.end(); ++it)
{
cout<<(*it)<<endl;
}
}
else
{
cout<<"data error"<<endl;
}
return 0;
}
输出结果:
5
5
5
6
6