stack design
getMinimum operation
algorithm optimization
data structures
O(1) complexity

design a stack such that getMinimum should be O1

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

When implementing a stack data structure, one of the frequently asked problems is to design it such that the getMinimum() function operates with a time complexity of O(1)O(1). This means that the stack should be able to return the minimum element in constant time, irrespective of its current state. To achieve this, various approaches have been devised. This article delves into an effective method leveraging two parallel stacks to keep track of the minimum element, ensuring both efficiency and simplicity.

Understanding the Stack Data Structure

A stack is a Last-In-First-Out (LIFO) data structure, where elements are added or removed from the top of the stack. The primary operations associated with a stack include:

  • push(x): Add element x to the top of the stack.
  • pop(): Remove the element from the top of the stack and return it.
  • top(): Return the element at the top of the stack without removing it.

The challenge lies in implementing getMinimum() that retrieves the minimum element without traversing the stack.

Dual Stack Approach

Concept

By maintaining two separate stacks, we can efficiently track the minimum element:

  1. Main Stack: This stack behaves like a regular stack, storing all the elements.
  2. Min Stack: This stack stores minimum values. The minStack ensures that each element in it is the minimum of all elements below it in the mainStack.

Implementation

Here's how the push, pop, top, and getMinimum operations are implemented using two stacks:

  • Push Operation:
    • Push the element onto the mainStack.
    • If the minStack is empty or the new element is less than or equal to the current minimum (top of the minStack), push it onto the minStack.
  • Pop Operation:
    • Pop the element from the mainStack.
    • If this element is equal to the top element of the minStack, pop it from the minStack as well.
  • Top Operation:
    • Return the top element of the mainStack.
  • Get Minimum Operation:
    • Return the top element of the minStack.

Example Implementation

Here's a Python example:

python
1class MinStack:
2    def __init__(self):
3        self.mainStack = []
4        self.minStack = []
5
6    def push(self, x):
7        self.mainStack.append(x)
8        if not self.minStack or x <= self.minStack[-1]:
9            self.minStack.append(x)
10
11    def pop(self):
12        if self.mainStack:
13            top = self.mainStack.pop()
14            if top == self.minStack[-1]:
15                self.minStack.pop()
16
17    def top(self):
18        if self.mainStack:
19            return self.mainStack[-1]
20        return None
21
22    def getMinimum(self):
23        if self.minStack:
24            return self.minStack[-1]
25        return None

Operation Analysis

The following table summarizes the operations and their respective time complexities:

OperationDescriptionTime Complexity
push(x)Push x to both mainStack and minStack if needed.O(1)O(1)
pop()Pop from mainStack and minStack if top elements match.O(1)O(1)
top()Retrieve the top element from mainStack.O(1)O(1)
getMinimum()Retrieve the minimum element from minStack.O(1)O(1)

Space Complexity

The space complexity of this approach is O(n)O(n), where nn is the number of elements in the stack. This is because, in the worst-case scenario, each element in the mainStack could also reside in the minStack if the sequence of inserted numbers is monotonically decreasing.

Advantages and Considerations

  • Efficiency: The dual stack method is efficient, with O(1)O(1) time complexity for all fundamental operations.
  • Simplicity: Implementing two stacks is straightforward and easy to understand.
  • Space Trade-off: While powerful, this method uses extra space for the minStack. In applications where memory is a constraint, other advanced methods like using a single stack with auxiliary data might be preferred.

Advanced Alternatives

While the dual stack method is optimal for most use cases, other methods such as augmenting the stack with differential data or adopting a linked list approach can also be considered for special use cases.

Overall, using a dual stack approach simplifies the problem of achieving O(1)O(1) time complexity for getMinimum(), offering a neat balance between computational and spatial efficiency. This structuring finds its use in numerous real-world applications where quick access to minimum values in a dynamic data set is crucial, such as financial systems handling real-time data and algorithmic trading platforms.


Course illustration
Course illustration

All Rights Reserved.