上次我们介绍了单调栈结构https://blog.csdn.net/hebtu666/article/details/82717317
这次介绍一种新的数据结构:双端队列:双端队列是指允许两端都可以进行入队和出队操作的队列,其元素的逻辑结构仍是线性结构。将队列的两端分别称为前端和后端,两端都可以入队和出队。
堆栈、队列和优先队列都可以采用双端队列来实现
本文介绍单调双端队列的原理及应用。
单调队列,顾名思义,就是一个元素单调的队列,那么就能保证队首的元素是最小(最大)的,从而满足最优性问题的需求。
给定一个长度为n的数列,一个k,求所有的min(ai,ai+1.....ai+k-1),i=0,1,....n-k
通俗一点说就是一个长度固定的滑动的窗口,求每个窗口内的最小值。
你当然可以暴力求解,依次遍历每个窗口.
介绍单调队列用法:我们维护一个单调队列
单调队列呢,以单调递增序列为例:
1、如果队列的长度一定,先判断队首元素是否在规定范围内,如果超范围则增长队首。
2、每次加入元素时和队尾比较,如果当前元素小于队尾且队列非空,则减小尾指针,队尾元素依次出队,直到满足队列的调性为止
我们说算法的优化就是重复计算过程的去除。
按窗口一次次遍历就是重复计算。最值信息没有利用好。
我们为什么可以这么维护?
首先,遍历到的元素肯定在队列元素之后。
其次,如果当前元素更小的话。
头部的值比当前元素大,头部还比当前元素先过期。所以以后计算再也不会用到它了。我们可以放心的去掉它。
下面给出代码和解释
int n,k;//长度为n的数列,窗口为k
int a[MAX_N];//数列
int b[MAX_N];//存放
int deq[MAX_N]//模拟队列void solve()
{int s = 0,t = 0;//头和尾for(int i=0;i<n;i++){//不满足单调,尾就弹出while(s<t && a[deq[t-1]]>=a[i])t--;//直到满足,放入deq[t++]=i;//计算窗口最大值if(i-k+1>=0)b[i-k+1]=a[deq[s];//判断头过期弹出if(deq[s]==i-k+1)s++;}
}
基本入门就到这里。