Design a max stack that supports push, pop, top, peekMax and popMax.
push(x) – Push element x onto stack. pop() – Remove the element on top of the stack and return it. top() – Get the element on the top. peekMax() – Retrieve the maximum element in the stack. popMax() – Retrieve the maximum element in the stack, and remove it. If you find more than one maximum elements, only remove the top-most one. Example 1:
Note: -1e7 <= x <= 1e7 Number of operations won’t exceed 10000. The last four operations won’t be called when stack is empty.
Solution:
Use two stacks to store the ordering of element and a maxStack.
For normal push, check if the value is greater than maxStack[-1]
Notice the popMax(), the element of that max item might not be stack[-1], so need to keep all element comes after current maximum(maxStack[-1]) in a tmp queue.
For example, since 1 comes after 5, it would not be pushed into maxStack at first. So once 5 is pop out, we need to push 1 back
defpopMax(self) -> int: q = deque() # to keep element until we find maxStack[-1] in stack while self.stack[-1] != self.maxStack[-1]: q.append(self.stack.pop()) self.stack.pop() res = self.maxStack.pop() # maxStack might be empty while q: ifnot self.maxStack or self.maxStack[-1] <= q[-1]: self.maxStack.append(q[-1]) self.stack.append(q.pop()) return res
/** * 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(); */
time complexity: $O()$ space complexity: $O()$ reference:
heap to find the max in O(logN) and do removal in O(1) with the help of dict and doubly linked list.
classDoubleLinkedList: def__init__(self, val=None): self.val = val self.next = None self.pre = None classMaxStack: def__init__(self): """ initialize your data structure here. """ self.stack = DoubleLinkedList(float('-inf')) # init a dummy node self.last = self.stack # reference the stack tail self.heap = [] self.hmap = defaultdict(list)
defpush(self, x: int) -> None: # O(logn) node = DoubleLinkedList(x) # update the tail self.last.next = node node.pre = self.last self.last = node # push -x to the min heap heappush(self.heap, -x) # append node the the map entry self.hmap[x].append(node) defpop(self) -> int: # O(1) # pop from the stack and remove from map num = self.last.val self.last = self.last.pre self.last.next = None self.hmap[num].pop() ifnot self.hmap[num]: del self.hmap[num] return num
deftop(self) -> int: # O(1) return self.last.val
defpeekMax(self) -> int: # O(logN) # during the pop(), we didn't remove the element from heap # So here is to remove the the poped elements from heap while -self.heap[0] notin self.hmap: heappop(self.heap) return -self.heap[0]
defpopMax(self) -> int: # O(logN) # get the top-most node from map num = self.peekMax() node = self.hmap[num].pop() ifnot self.hmap[num]: del self.hmap[num] # update the tail reference if node == self.last: self.last = self.last.pre # remove the node from stack if node.pre: node.pre.next = node.next if node.next: node.next.pre = node.pre return num