Design a max stack data structure that supports the stack operations and supports finding the stack's maximum element.
Implement the MaxStack class:
MaxStack() Initializes the stack object.void push(int x) Pushes element x onto the stack.int pop() Removes the element on top of the stack and returns it.int top() Gets the element on the top of the stack without removing it.int peekMax() Retrieves the maximum element in the stack without removing it.int popMax() Retrieves the maximum element in the stack and removes it. If there is more than one maximum element, only remove the top-most one.You must come up with a solution that supports O(1) for each top call and O(logn) for each other call.
Example 1:
Input ["MaxStack", "push", "push", "push", "top", "popMax", "top", "peekMax", "pop", "top"] [[], [5], [1], [5], [], [], [], [], [], []] Output [null, null, null, null, 5, 5, 1, 5, 1, 5] Explanation MaxStack stk = new MaxStack(); stk.push(5); // [5] the top of the stack and the maximum number is 5. stk.push(1); // [5, 1] the top of the stack is 1, but the maximum is 5. stk.push(5); // [5, 1, 5] the top of the stack is 5, which is also the maximum, because it is the top most one. stk.top(); // return 5, [5, 1, 5] the stack did not change. stk.popMax(); // return 5, [5, 1] the stack is changed now, and the top is different from the max. stk.top(); // return 1, [5, 1] the stack did not change. stk.peekMax(); // return 5, [5, 1] the stack did not change. stk.pop(); // return 1, [5] the top of the stack and the max element is now 5. stk.top(); // return 5, [5] the stack did not change.
Constraints:
-107 <= x <= 107105 calls will be made to push, pop, top, peekMax, and popMax.pop, top, peekMax, or popMax is called.Problem Overview: Design a stack that behaves like a normal stack but also supports two extra operations: peekMax() to view the maximum element and popMax() to remove the maximum element. If multiple elements share the maximum value, remove the one closest to the top. The challenge is maintaining both stack order and fast access to the current maximum.
Approach 1: Simple Stack Scan (O(n) popMax)
Use a regular stack to store values. push, pop, and top work in O(1) time. For peekMax(), scan the stack to find the maximum element in O(n) time. For popMax(), repeatedly pop elements into a temporary stack until the maximum is found, remove it, then restore the remaining elements. Time complexity becomes O(n) for both max operations with O(n) auxiliary space during the operation.
Approach 2: Two Stacks (O(n) popMax)
Maintain two stacks: the main stack and a max-tracking stack that stores the maximum value at each level. Each push updates the max stack with max(current, previousMax). peekMax() becomes O(1). However, removing the maximum still requires popping elements until the max appears, then pushing them back. That makes popMax() O(n) time and O(n) temporary space. This improves read performance but not deletion of arbitrary maximum elements.
Approach 3: Doubly Linked List + Ordered Map (O(log n))
The optimal design combines a doubly linked list with an ordered map (like TreeMap or balanced BST). The doubly linked list maintains stack order, enabling push, pop, and top in O(1). The ordered map stores values as keys and a list of node references as values. This lets you locate the largest key quickly.
When pushing, insert a node at the tail of the linked list and store its reference in the ordered map. For peekMax(), retrieve the largest key in the map in O(log n) or O(1) depending on implementation. For popMax(), find the largest value, remove the most recently inserted node from its node list, and unlink that node from the doubly linked list. Both structures stay synchronized.
This design efficiently supports all operations: linked list handles stack order while the ordered structure provides fast maximum lookup. Time complexity is O(log n) for push and popMax(), and O(1) for standard stack operations. Space complexity is O(n). It demonstrates how combining a linked list with an ordered set solves conflicting access patterns.
Recommended for interviews: The doubly linked list + ordered map approach is what interviewers typically expect for this hard design problem. Showing the brute-force stack scan first demonstrates understanding of the constraints, while transitioning to the balanced-map design shows strong data structure design skills.
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Simple Stack Scan | push/pop O(1), peekMax O(n), popMax O(n) | O(n) | Good for understanding the problem or quick prototypes |
| Two Stacks (Stack + Max Stack) | push/pop/top O(1), peekMax O(1), popMax O(n) | O(n) | When frequent max lookups are needed but popMax is rare |
| Doubly Linked List + Ordered Map | push O(log n), pop O(1), peekMax O(log n), popMax O(log n) | O(n) | Optimal interview solution supporting fast stack and max operations |
LeetCode 716 | Max Stack • leetuition • 11,996 views views
Watch 9 more video solutions →Practice Max Stack with our built-in code editor and test cases.
Practice on FleetCode