Besides the standard stack operations push(x), pop(), and peek(), we also need to support a heap operation getMin() in O(1) time. The first thought can be use a variable to keep track of the minimum value that works but when the min value gets popped out, we need to restore the second smallest value. This insight calls for a special type of stack - monotonic stack.
Monotonic Stack
A monotonic stack is a stack in which its elements are strictly increasing or decreasing. In this case, we want to use a decreasing stack to keep track of all the min values.
class MinStack {
Stack<Integer> stack;
Stack<Integer> decStack;
public MinStack() {
stack = new Stack<Integer>();
decStack = new Stack<Integer>();
}
public void push(int x) {
stack.push(x);
if (decStack.isEmpty() || x <= decStack.peek()) {
decStack.push(x);
}
}
public void pop() {
if (stack.pop().equals(decStack.peek())) {
decStack.pop();
}
}
public int top() {
return stack.peek();
}
public int getMin() {
return decStack.peek();
}
}
Design a data structure that supports push(x), pop(), top(), peekMax() and popMax().
Analysis
In addition to function like a normal max stack, its an additional function popMax().
Let's implement the normal functionalities first, then look into popMax().
It turns we really just have to brute force this with two stacks. Using a temp stack to store the elements until we find max and pop it. The tricky part is that we have to push it back and update incStack.
class MaxStack {
Stack<Integer> stack;
Stack<Integer> incStack;
public MaxStack() {
stack = new Stack<Integer>();
incStack = new Stack<Integer>();
}
public void push(int x) {
stack.push(x);
if (incStack.isEmpty() || x >= incStack.peek()) {
incStack.push(x);
}
}
public int pop() {
int pop = stack.pop();
if (pop == incStack.peek()) {
incStack.pop();
}
return pop;
}
public int top() {
return stack.peek();
}
public int peekMax() {
return incStack.peek();
}
public int popMax() {
if (stack.isEmpty()) {
return -1;
}
int max = incStack.pop();
removeMax(max); // remove max from stack and update incStack
return max;
}
// remove the max value from stack
private void removeMax(int max) {
// temp will store all the elements that are not max
Stack<Integer> temp = new Stack<>();
while (stack.peek() != max) {
temp.push(stack.pop());
}
// found the max
stack.pop();
// push these elements back
while (!temp.isEmpty()) {
push(temp.pop().intValue());
}
}
}