单调队列分为单调递增队列和单调递减队列,由于二者差不多,这里只介绍下单调递减队列。
用途:
单调队列可以用来维护区间最值。
单调递减队列维护区间最大值,单调递增队列维护区间最大值。
实现:
现在我们用单调递减队列维护长度为L的区间的最大值。现将下标为x的元素a入队。用b表示队列尾元素。(这里可能描述的不是很清,因为这个结构的使用违背了队列的用法,可以看下面的例子)
1.b>a
b出队,直到队列为空,或b<a,则a入队。
2.假设队列首元素c下标为y
y < x-L+1,则c出队,直到y>=x-L+1。
3.此时队列首元素c是区间[x-L+1,x]的最大值。
例子:
给定数列:3 ,1 ,5 , 7 ,4 ,2 , 1。维护区间长度为3的最大值
1.3入队 3
2.1入队 3,1
3.3,1出队,5入队 5 区间[1,3]的最大值为5
4.5出队,7入队 7 区间[2,4]的最大值为7
5.4入队 7,4 区间[3,5]的最大值为7
6.2入队 7,4,2 区间[4,6]的最大值为7
7.1入队,7出队 4,2,1 区间[5,7]的最大值为4
性质:
1.队列里的元素是单调递减的。
2.假如维护区间长度为L的最大值,刚入队的元素下标为x,则队列首元素是区间[x-L+1,x]的最大值。
3.由于每个元素只会入队和出队各一次,所以复杂度为0(n)。
现在重点介绍下性质2,我们应该好好体会一下这种思想。
现在我们求出区间[x,y]的最大值a,此时我们要求[x+1,y+1]区间的最大值,假如下标为y+1的元素b > a,那么该区间的最大值肯定是b,但b < a呢?拿b和区间[x+1,y]的所有数比较一次?这样复杂度太高了。我们想一下我们在求[x,y]的最大值时,[x+1,y]的信息我们都是知道的。我们可以把这些值保存下来,但对于i < j && val[i] < val[j]的元素i我们是没有必要保存的,我们只要保存j就可以了(仔细体会下)。这时我们按照前面的方法维护单调队列。此时队首元素为v,下标为t(x+1 <= t <= y+1),为啥t就是区间[x+1,y+1]的最大值呢。因为这是递减队列,所以在区间[x+1,y+1]中v前面的元素必然小于v,不然会留在队列中,v后面的元素也必然小于v,不然v不会留在队列中,所以v是最大值。