单调队列,顾名思义就是队中元素都是单调的队列,它们即可以是单调递增,也可以是单调递减的,单调队列有着重要的应用。
通过几道经典题目来熟悉单调队列:
1.集合
若一个数x在集合中,则2x+1,3x+1也在集合中,已知开始1在集合中,求集合第n大的数字。
分析:如果用朴素的方法对付不了很大的数据,可以维护三个单调递增队列,一个队列保存集合中的数a,另外两个队列分别保存由2x+1和3x+1产生的数,命名为p,q,每次由a中队首产生两个数,分别进入p,q中,将p,q的队首元素比较,小的元素入a队同时对应队列队首指针后移,知道a中有n个数为止,时间效率O(n)。
2.合并果子
n堆果子,每次两两合并,合并代价为合并的两堆果子之和,求全部合并为一堆的最小代价。
分析:先按果子数从小到大对所有堆进行排序,然后维护两个单调递增队列a,b,分别表示保存前的值和合并后的新值。每次合并比较a队首两个元素之和,b队首两个元素之和,两个队列队首元素之和,选取最小值存入b中并将a,b指针对应移动,最终当b中只剩一个值时结束,时间效率O(n),但还要加上排序的时间,总效率为O(nlog(n)+n)。
3.滑动窗口
求n个数排成一列,求每个长为k的区间中的最小值和最大值。
分析:对于求最小值,维护一个单调递增序列,同时要记录队中每一个元素进队时间,按读入的顺序选取待加入的数,每一次将队尾元素和待加入的元素比较,若队尾元素较大则队尾指针减一再比较队尾,直到队尾元素小于待加入的数或队空,将元素进队,如果队首元素从加入到现在时间超出了k,队首指针加一,由于每次一个数进入队列,可保证后面的数在当前时间不超过k,故超出时间则队首指针只要加一即可,由于单调性,每一次队首元素为该区间最小值,最大数处理同最小数,只是维护的是单调递减序列而已。每个数进队出队一次,时间效率为O(n)级别的。