https://www.cnblogs.com/haozhengfei/p/a14049ec0869a8125a69f3af37471c77.html
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
/*
一个整形数组arr和一个大小为w的窗口从数组的最左边滑倒最右边,
窗口每次向右滑一个元素。返回一个长度为n-w+1的数组res,res[i]
表示每一种窗口状态下的最大值。以数组[4,3,5,4,3,3,6,7]为例。
因为第一个窗口[4,3,5]的最大值为5,第二个窗口[3,5,4]的最大值为
5,,,所以最终返回[5,5,5,4,6,7]
利用双端队列:
维护一个双端队列,
首先对w窗口内的0->(w-1)号元素arr[i],队列中总是存储从左至右是
严格降序的元素的下标,比如头两个元素的下标{0,1},分别对应元素4>3,
或者当前元素arr[i]大于等于队列中所有下标的元素,那就只存储当前
最大元素的下标,小于等于当前最大元素的其他下标都被弹出队列。此时
起始w窗口中最大值总是队列头部下标对应的元素。
比如[5,4,3,2,1]
然后向右滑动窗口考察到元素arr[i],首先判断队列中头部下标是否超出了
i-w,如果超出(小于等于)i-w则说明队列中的最大值元素属于上一个窗口,
那首先将队列头元素弹出,因为当前队列中最多w个下标,且只要队列中有不少于
1个下标,那后面的下标肯定要高于队列头的下标且对应元素小于队列头下标对应
的元素,如果大于等于队列头下标的元素那一定已经将队列所有下标都弹出只留下
上一个窗口的最右边的最大值下标了
*/
void getWindowMax(vector<int> arr,int m,vector<int>&res){
if(m>arr.size())return;
//首先生成前m个元素的队列
deque<int> deq;
for(int i(0);i<m;i++){
if(deq.size()<=0) deq.push_back(i);
else{
if(arr[i]<arr[*deq.rbegin()]) deq.push_back(i);
else{
while(deq.size()>0 && arr[i]>=arr[*deq.rbegin()]){
//等于也要弹出并替换,用新的值替换旧的值,滑动窗口后肯定要用新的值不用旧的值
deq.pop_back();
}
deq.push_back(i);
}
}
}
res.push_back(arr[*deq.begin()]);
//然后滑动窗口
//队列中始终保存有前一窗口中左边最大元素及右边的较小元素下标,后一窗口将只前一窗口的下标排除后
//,前一窗口右边那些次小的元素下标再和当前窗口新增的元素比较大小,替换(将前面小元素都弹出
//,因为当前元素已经最大,在下个窗口中也只需与当前最大元素比较)或者当前新增元素较小的话补充进
//队列,以待参与下一个窗口的最大值判断
for(int i(m);i<arr.size();i++){
//首先检查排除下标队列中头部下标是否超出当前窗口
if((*deq.begin())<i-m+1) deq.pop_front();
//然后将当前元素新增到队列:
while(deq.size()>0 && arr[i]>=arr[*deq.rbegin()]) deq.pop_back();
deq.push_back(i);
res.push_back(arr[*deq.begin()]);
}
}
int main(int argc,char *argv[]){
vector<int> arr,res;
int arr2[]={4,3,5,4,3,3,6,7};
for(int i(0);i<8;i++)arr.push_back(arr2[i]);
getWindowMax(arr,3,res);
for(int &rele:res)std::cout<<rele<<"\t";
std::cout<<"\n";
}