单调队列总结
单调队列是指队列中的元素是按照单调递增或者递减的顺序排列的,一般常用于需要动态求某个范围的最值的情况
单调队列一般使用双向队列来实现,具体实现细节见下面:
// 创建单调队列
Deque<Integer> monoQueue = new LinkedList<>();
// 增加元素,从队列尾部增加元素,如果有比当前元素小的则弹出,维持单调队列
// 因为单调队列是为了维护当前范围内的最大值,那么比当前元素小的元素必然不可能是最大值,因此这些元素删除不会有影响
public void push_back(int value) {
while (!monoQueue.isEmpty() && monoQueue.peek() < value) {
monoQueue.pollLast();
}
monoQueue.offer(value);
}
// 删除元素:需要满足条件,比如单调队列头元素等于...,则删除
队列的最大值
剑指Offer 59- II 队列的最大值,为了实时维护当前队列中的最大值,可以使用单调递减队列,队头元素表示当前队列中的最大值,因此增加元素时和之前一样,而删除元素时当单调队列的队头元素等于队列的队头元素时,删除,否则不必。因为队列的队头元素如果是队列中的最大元素,那么必然单调队列的队头元素就等于队列的队头元素,因此删除;而如果它不是最大元素,那么必然队列后面的元素是最大元素,则单调队列的队头元素就是队列后面的元素,在单调队列中队列头元素早已经被删去了,不用再维护。
class MaxQueue {
private Queue<Integer> queue;
private Deque<Integer> maxQueue;
public MaxQueue() {
queue = new LinkedList<>();
maxQueue = new LinkedList<>();
}
public int max_value() {
if (queue.isEmpty())
return -1;
return maxQueue.peek();
}
public void push_back(int value) {
queue.offer(value);
while (!maxQueue.isEmpty() && maxQueue.peekLast() < value) {
maxQueue.pollLast();
}
maxQueue.offer(value);
}
public int pop_front() {
if (queue.isEmpty())
return -1;
int res = queue.poll();
if (maxQueue.peek() == res) {
maxQueue.poll();
}
return res;
}
}
/**
* Your MaxQueue object will be instantiated and called as such:
* MaxQueue obj = new MaxQueue();
* int param_1 = obj.max_value();
* obj.push_back(value);
* int param_3 = obj.pop_front();
*/
从这道题我们可以看出,单调队列其实对应了队列的元素的状态,但不是一一对应的。
还有类似的题可以使用单调队列,即 剑指Offer 59-I 滑动窗口的最大值
单调栈
既然有单调队列,那么就有单调栈。可以看这道题 剑指Offer 30.包含min函数的栈
单调栈是指单调栈中每一个元素都是对应栈中的最小值,单调栈中的每一个元素都和栈中元素一一对应。所以,压栈的时候,需要压入一个栈元素和单调栈顶元素的最小值;退栈的时候,同步推出即可,求最小值只需返回单调栈栈顶元素,如果单调栈不为空
class MinStack {
private Deque<Integer> stack;
private Deque<Integer> minStack;
/** initialize your data structure here. */
public MinStack() {
stack = new LinkedList<>();
minStack = new LinkedList<>();
}
public void push(int x) {
stack.push(x);
int min;
if (minStack.isEmpty()) {
min = x;
} else {
min = Math.min(minStack.peek(), x);
}
minStack.push(min);
}
public void pop() {
if (stack.isEmpty()) {
return;
}
stack.pop();
minStack.pop();
}
public int top() {
if (stack.isEmpty())
return -1;
return stack.peek();
}
public int min() {
if (minStack.isEmpty())
return -1;
return minStack.peek();
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(x);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.min();
*/