唯一的难点在popMax(),因为只需要pop max值对应的元素,因此需要辅助stack来存pop出来的元素,当pop 完 max 元素之后,再将辅助stack中元素push回原来的stack即可,但是这是要用MaxStack class本身的push(int x),因为需要更新此时stack中的max。此外可以进一步优化push(),再创建一个push(Element e),这样就可以不用每次stack.push时都new一下Element。
Time: O(n)
Space: O(n)
classMaxStack {classElement {int val;int max;publicElement(int val,int max) {this.val= val;this.max= max; } }privateDeque<Element> stack;privateDeque<Element> aux; /** initialize your data structure here. */publicMaxStack() { stack =newArrayDeque<Element>(); aux =newArrayDeque<Element>(); }publicvoidpush(int x) {int max = x;if (!stack.isEmpty()) { max =Math.max(x,stack.peek().max); }stack.push(newElement(x, max)); }publicintpop() {if (stack.isEmpty()) {return-1; }returnstack.pop().val; }publicinttop() {if (stack.isEmpty()) {return-1; }returnstack.peek().val; }publicintpeekMax() {if (stack.isEmpty()) {return-1; }returnstack.peek().max; }publicintpopMax() {if (stack.isEmpty()) {return-1; }int max =stack.peek().max;while (!stack.isEmpty() &&stack.peek().val!= max) {aux.push(stack.pop()); }// pop the maxif (!stack.isEmpty()) {stack.pop(); }while (!aux.isEmpty()) {push(aux.pop().val); }return max; }}/** * Your MaxStack object will be instantiated and called as such: * MaxStack obj = new MaxStack(); * obj.push(x); * int param_2 = obj.pop(); * int param_3 = obj.top(); * int param_4 = obj.peekMax(); * int param_5 = obj.popMax(); */
Space Optimized - push(Element e) to reuse Element objects
Time: 81 ms, faster than 94.91%
Space: 40.3 MB, less than 100.00%
classMaxStack {classElement {int val;int max;publicElement(int val,int max) {this.val= val;this.max= max; } }privateDeque<Element> stack;privateDeque<Element> aux; /** initialize your data structure here. */publicMaxStack() { stack =newArrayDeque<Element>(); aux =newArrayDeque<Element>(); }publicvoidpush(int x) {int max = x;if (!stack.isEmpty()) { max =Math.max(x,stack.peek().max); }stack.push(newElement(x, max)); }privatevoidpush(Element e) {int max =e.val;if (!stack.isEmpty()) { max =Math.max(e.val,stack.peek().max); }e.max= max;stack.push(e); }publicintpop() {returnstack.pop().val; }publicinttop() {returnstack.peek().val; }publicintpeekMax() {returnstack.peek().max; }publicintpopMax() {int max =stack.peek().max;while (!stack.isEmpty() &&stack.peek().val!= max) {aux.push(stack.pop()); }// pop the maxif (!stack.isEmpty()) {stack.pop(); }while (!aux.isEmpty()) {push(aux.pop()); }return max; }}/** * Your MaxStack object will be instantiated and called as such: * MaxStack obj = new MaxStack(); * obj.push(x); * int param_2 = obj.pop(); * int param_3 = obj.top(); * int param_4 = obj.peekMax(); * int param_5 = obj.popMax(); */
LeetCode Official - Approach #1: Two Stacks
For peekMax, we remember the largest value we've seen on the side. For example if we add [2, 1, 5, 3, 9] in stack , we'll store [2, 2, 5, 5, 9] in maxStack. This works seamlessly withpopoperations, and also it's easy to compute: it's just the maximum of the element we are adding and the previous maximum.
ForpopMax, we know what the current maximum (peekMax) is. We can pop until we find that maximum, then push the popped elements back on the stack.
Time Complexity: O(N) for the popMaxoperation, and O(1) for the other operations, where N is the number of operations performed.
Space Complexity: O(N), the maximum size of the stack.
classMaxStack {Stack<Integer> stack;Stack<Integer> maxStack;publicMaxStack() { stack =newStack(); maxStack =newStack(); }publicvoidpush(int x) {int max =maxStack.isEmpty() ? x :maxStack.peek();maxStack.push(max > x ? max : x);stack.push(x); }publicintpop() {maxStack.pop();returnstack.pop(); }publicinttop() {returnstack.peek(); }publicintpeekMax() {returnmaxStack.peek(); }publicintpopMax() {int max =peekMax();Stack<Integer> buffer =newStack();while (top()!= max) buffer.push(pop());pop();while (!buffer.isEmpty()) push(buffer.pop());return max; }}
LeetCode Official - Approach #2: Double Linked List + TreeMap
Intuition
Using structures like Array or Stack will never let uspopMaxquickly. We turn our attention to tree and linked-list structures that have a lower time complexity for removal, with the aim of makingpopMaxfaster than O(N) time complexity.
Say we have a double linked list as our "stack". This reduces the problem to finding which node to remove, since we can remove nodes in O(1) time.
We can use a TreeMap mapping values to a list of nodes to answer this question. TreeMap can find the largest value, insert values, and delete values, all in O(logN) time.
Algorithm
Let's store the stack as a double linked listdll, and store amapfromvalueto aListofNode.
When weMaxStack.push(x), we add a node to ourdll, and add or update our entrymap.get(x).add(node).
When weMaxStack.pop(), we find the valueval = dll.pop(), and remove the node from ourmap, deleting the entry if it was the last one.
When weMaxStack.popMax(), we use themapto find the relevant node tounlink, and return it's value.
The above operations are more clear given that we have a workingDoubleLinkedListclass. The implementation provided usesheadandtail_sentinels_to simplify the relevantDoubleLinkedListoperations.
A Python implementation was not included for this approach because there is no analog to_TreeMap_available.
Time Complexity: O(logN) for all operations exceptpeekwhich is O(1), where N is the number of operations performed. Most operations involvingTreeMapare O(logN).
Space Complexity: O(N), the size of the data structures used.