Min Stack Design in DSA C - Time & Space Complexity
We want to understand how fast the Min Stack operations run as the number of elements grows.
Specifically, how does the time to push, pop, or get the minimum change with more items?
Analyze the time complexity of the following Min Stack code snippet.
typedef struct {
int *stack;
int *minStack;
int top;
int capacity;
} MinStack;
void push(MinStack* obj, int val) {
obj->stack[++obj->top] = val;
int minVal = obj->top == 0 ? val : (val < obj->minStack[obj->top - 1] ? val : obj->minStack[obj->top - 1]);
obj->minStack[obj->top] = minVal;
}
void pop(MinStack* obj) {
if (obj->top >= 0) obj->top--;
}
int getMin(MinStack* obj) {
return obj->minStack[obj->top];
}
This code keeps track of the minimum value at each stack level to allow quick minimum retrieval.
Look for loops or repeated steps inside each operation.
- Primary operation: Each push, pop, and getMin runs a fixed number of steps without loops.
- How many times: Each operation runs once per call, no matter how many elements are in the stack.
Each operation does a constant amount of work regardless of stack size.
| Input Size (n) | Approx. Operations per push/pop/getMin |
|---|---|
| 10 | 5-6 steps |
| 100 | 5-6 steps |
| 1000 | 5-6 steps |
Pattern observation: The number of steps stays the same no matter how many elements are in the stack.
Time Complexity: O(1)
This means each operation takes the same short time no matter how big the stack is.
[X] Wrong: "Finding the minimum must scan all elements, so it takes longer as stack grows."
[OK] Correct: The min stack stores the minimum at each step, so getMin just reads one value instantly.
Knowing how to keep track of minimum values efficiently shows your skill in designing smart data structures.
"What if we used only one stack and searched for the minimum each time getMin is called? How would the time complexity change?"
Practice
Min Stack data structure?Solution
Step 1: Understand Min Stack functionality
A Min Stack is designed to allow retrieval of the minimum element quickly, usually in constant time.Step 2: Compare with other options
Sorting or queue behavior is not the main goal of a Min Stack; it focuses on minimum element retrieval.Final Answer:
To retrieve the minimum element in constant time -> Option BQuick Check:
Min Stack = fast minimum retrieval [OK]
- Confusing Min Stack with sorting algorithms
- Thinking it behaves like a queue
- Assuming it reverses elements
Solution
Step 1: Identify required fields for Min Stack node
A Min Stack node needs to store the value, a pointer to the next node, and the minimum value at that node.Step 2: Match with options
typedef struct Node { int value; struct Node* next; int min; } Node; includes value, next pointer, and min field, which is correct for Min Stack implementation.Final Answer:
typedef struct Node { int value; struct Node* next; int min; } Node; -> Option AQuick Check:
Node stores value, next, and min [OK]
- Omitting the min field in node
- Using prev pointer instead of next
- Not using struct pointer for next
void push(Node** top, int x) {
Node* newNode = malloc(sizeof(Node));
newNode->value = x;
if (*top == NULL) {
newNode->min = x;
} else {
newNode->min = (x < (*top)->min) ? x : (*top)->min;
}
newNode->next = *top;
*top = newNode;
} What will be the minimum value after pushing elements 3, 5, 2 in this order on an empty stack?Solution
Step 1: Push 3 on empty stack
Stack top is NULL, so min = 3.Step 2: Push 5
Compare 5 with current min 3; min remains 3.Step 3: Push 2
Compare 2 with current min 3; min updates to 2.Final Answer:
2 -> Option AQuick Check:
Minimum after pushes = 2 [OK]
- Not updating min on push
- Confusing min with last pushed value
- Assuming min resets on each push
int pop(Node** top) {
if (*top == NULL) return -1;
int val = (*top)->value;
free(*top);
*top = (*top)->next;
return val;
}Solution
Step 1: Analyze order of operations
The code frees *top, then accesses (*top)->next, which is invalid after free.Step 2: Correct order
Should save next pointer before freeing current node to avoid invalid access.Final Answer:
Accessing (*top)->next after freeing *top -> Option CQuick Check:
Free before next access causes error [OK]
- Freeing node before accessing next
- Ignoring NULL check
- Returning value after free without saving
push, pop, and getMin all in O(1) time using two stacks. Which approach correctly implements getMin?Solution
Step 1: Understand two-stack Min Stack design
One stack stores all values; the second stack keeps track of minimums for O(1) retrieval.Step 2: Evaluate options
Maintain a second stack that stores the minimum values; push new min or duplicate current min on push correctly describes pushing new minimum or current minimum duplicate onto second stack.Final Answer:
Maintain a second stack that stores the minimum values; push new min or duplicate current min on push -> Option DQuick Check:
Two stacks: one for values, one for mins [OK]
- Sorting stack on every push (slow)
- Searching stack on getMin (not O(1))
- Using queue instead of stack
Ready to prove it?
Pass the test and this pattern moves unknown
