顾名思义,就是用一点巧妙的方法,使得队列中的元素全是单调递增或递减,常常用来解决滑动窗口的一系列问题。
好了,废话不多说,上正题。
模板思路在代码中,超详细,看完你就悟了。
利用双端队列实现
初始化双端队列
void init()
{
//必须从前边删
while (!q1.empty()) q1.pop_front();
while (!q2.empty()) q2.pop_front();
}
维护队头是最大元素
k是区间范围。
struct node{
int order;//对应下标
int value;//对应值
}tmp;
deque<node>vis;
int main()
{
int n,k,t;
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
{
scanf("%d",&t);//当前值
// 当队列不为空,i是当前值得小标与队头元素下标之差大于等于k
//表明,虽然你队头大,但是已经不在有效范围了,所以要丢掉
if(!vis.empty() && i-vis.front().order>=k) vis.pop_front();
// 队列不为空,因为要维护的队列是队头是最大的,那么这个队列就
//是一个递减队列(想一下),所以当前值要比队尾小才可以,
//否则就将队尾元素丢掉,直到队尾比当前值小,或队列为空
while(!vis.empty() && vis.back().value<=t) vis.pop_back();
tmp.order=i;
tmp.value=t;
vis.push_back(tmp);
if(i>=k-1)
{
printf("%d\n",vis.front().value);
}
}
}
维护队头是最小元素
```cpp
struct node{
int order;//对应下标
int value;//对应值
}tmp;
deque<node>vis;
int main()
{
int n,k,t;
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
{
scanf("%d",&t);//当前值
if(!vis.empty() && i-vis.front().order>=k) vis.pop_front();
// 其余都一样,只不过下面这一行,变成当前值要大于队尾,
//结合上面想想就出来了,因为是要维护一个递增队列嘛
while(!vis.empty() && vis.back().value>=t) vis.pop_back();
tmp.order=i;
tmp.value=t;
vis.push_back(tmp);
if(i>=k-1)
{
printf("%d\n",vis.front().value);
}
}
}
利用数组实现
维护队头是最大元素
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
//存的是下标
vector<int> q(nums.size(),0);
vector<int> vec;
int tail = 0;//队尾指针
int head = 0;//队头指针
for(int i = 0;i< nums.size();i++){
//淘汰操作
//和上边对比下,队列不为空,不就是队尾指针大于队头指针嘛
//nums[i] 当前值,nums[q[tail-1]] 队尾值
// 丢掉队尾元素,不就是将队尾指针前移嘛
while(tail > head && nums[i] >= nums[q[tail-1]]) tail--;
//尾插操作
q[tail++] = i;
//过期头删操作
//q[head] 不就是对首小标嘛
if(i - q[head] >= k) head++;
if(i >= k)
vec.push_back(nums[q[head]]);
}
return vec;
}
看到这里大家有没有枉然大悟呀