滑动窗口问题
描述:
给定一个数组和一个指定长度的窗口,窗口每次滑动一个距离,求窗口在滑动的过程当中每个窗口当中的
最大和最小值。
思路:
首先想到的是暴力解法,搜索n-k+1个窗口,将每个窗口中的最大和最小值存储起来。此时的时间复杂度为
O(N*K)。该思路的代码如下:
#include<iostream> #include<vector> using namespace std; //使用滑动窗口来,在每个滑动窗口当中搜索最大和最下值,时间复杂度为O(N*K) int main() { int n,k; cin>>n>>k; vector<int> nums(n,0); for(int i=1;i<=n;i++) cin>>nums[i-1]; //逐个窗口查找最大和最小的值 vector<int> vmax; vector<int> vmin; int max,min; for(int i=0;i<=n-k;i++){ max=nums[i]; min=nums[i]; for(int j=0;j<k;j++) { if(nums[i+j]>max) max=nums[i+j]; if(nums[i+j]<min) min=nums[i+j]; } vmax.push_back(max); vmin.push_back(min); } for(int elem:vmin) cout<<elem<<" "; cout<<endl; for(int elem:vmax) cout<<elem<<" "; cout<<endl; return 0; }
上述方法的时间复杂度较高,考虑采用双端队列的数据结构。从队列的队头和队尾出队,队头存放的元素是当前窗口
最大值的坐标,队头出队时表示当前的最大值已经不在当前的窗口当中的了,队尾出队时是为了保证队头所存放元素的序
号一直为当前窗口中最大元素的序号。
#include<iostream> #include<deque> #include<vector> using namespace std; //用来存放窗口移动过程当中的最大值序列 vector<int> res; vector<int> res2; int getmax(vector<int>& nums,int size) { //双端队列用来保存遍历过程当中产生的最大值 deque<int> pos; //队列当中维持着长度为窗口长度的序列 for(int i=0;i<nums.size();i++) { //队头元素的坐标恰好为将要出队元素的坐标 if(!pos.empty()&&pos.front()==(i-size)) pos.pop_front(); //入队当前元素之前出队所有比其小的元素,确保队首的始终为当前窗口的最大值 while(!pos.empty()&&nums[pos.back()]<nums[i]) pos.pop_back(); pos.push_back(i); //队列当前的元素,插入了当前的元素后判断的最大值 if(i>=(size-1)) res.push_back(nums[pos.front()]); } } int getmin(vector<int>& nums,int size) { deque<int> pos; for(int i=0;i<nums.size();i++) { //判断当前的队头元素是否位于窗口之外 if(!pos.empty()&&pos.front()==(i-size)) pos.pop_front(); //向队列当中插入元素,包含当前元素的窗口当中被弹出的元素不可能为最大值的 while (!pos.empty()&&nums[pos.back()]>nums[i]) { pos.pop_back(); } pos.push_back(i); //从队头当中取出最小值即可 if(i>=size-1) res2.push_back(nums[pos.front()]); } } int main() { int n,k; cin>>n>>k; vector<int> nums(n,0); for(int i=0;i<n;i++) cin>>nums[i]; getmax(nums,k); getmin(nums,k); for(auto elem:res2) cout<<elem<<" "; cout<<endl; for(auto elem:res) cout<<elem<<" "; cout<<endl; return 0; }
使用了双端队列之后,生成窗口的最大值数组的时间复杂度变成了线性的。

浙公网安备 33010602011771号