本人是大一计算机专业在校学生,第一次发表笔记文章,若有写的不好的地方,请多多指教!
一:单调队列介绍:
底层是双端队列deque(STL,自己手写也可以)
其对于deque的操作方面只涉及到:
deque<int> de;
①从队尾插入 de.push_back(value);
②从队首弹出 de.pop_front();
单调队列的特性:
①只能从队尾插入。
②从队首开始,需要满足元素的单调性(单调递增,单调递减,单调不增,单调不减)。
③队首就是最优解。
二:单调队列的应用方面
①窗口问题(洛谷P1886)。
②数组的最大子序和问题。
三:如何使用单调队列求解窗口问题
首先,单调队列的存储方式与所求最值是相反的。
例如,我需要在一个窗口中求最大值,那么单调队列的存储方式必须递减存储,反之,递增存储。
注意: 往队列存储元素的过程中我们采用存储原数组下标的方式进行存储,这样拿出的队首元素我们可以直接下标索引法输出。
操作过程:
设窗口大小k=3;
并且以求最大值为例子,那么队列的元素必须单调递减
一:剪枝过程:
①判断队首元素有没有在窗口内,如果没有,需要弹出,原理图如下所示:
代码为:
判断条件为de.front()<i-k+1;
②对每个插入队尾的元素下标做处理(用while循环,因为要处理彻底)
就拿求最大值来说,队首一定要为最大值,因此插入的元素中(队列元素为原数组的下标),需要不断与队尾值的原数组索引做比较,即比较arr[i]和arr[de.back()],如果不符合,即arr[i]>=arr[de.back()]时,需要弹出队尾元素,然后在和新的队尾做比较。
此过程代码为:
二,每步的必须操作:
剪枝完之后,我们直接de.push_back(value);
特别注意:必须先剪枝才能push_back(),否则剪枝过程会把已经插入的元素删除!
三:判断输出:
什么时候需要输出?当窗口被填满时就要输出,当数组在第一次填满窗口前,状态
是这样的:
判断条件的代码为:
以上就是全过程,我们看一下完整代码:
四:单调队列的优势:
问:为什么要用单调队列?
答:更快,例如求解窗口问题时,暴力的方法时间复杂度为O(n^2),而单调队列的时间复杂度为O(n)。