Implementing the Stack
A Stack is an Abstract Data Type (ADT). We can build it using:
- Array: Fast access, cache-friendly.
- Linked List: Dynamic size, no resizing cost.
1. Core Operations
All Stack operations must be O(1).
- Push(val): Add
valto the top. - Pop(): Remove and return the top element.
- Peek(): Return the top element without removing it.
- IsEmpty(): Check if the stack is empty.
2. Java & Go: The Right Way
Java
import java.util.ArrayDeque;
import java.util.Deque;
public class StackDemo {
public void demo() {
Deque<Integer> stack = new ArrayDeque<>();
stack.push(10); // O(1)
stack.push(20);
int top = stack.peek(); // 20
int popped = stack.pop(); // 20
boolean isEmpty = stack.isEmpty(); // false
}
}
Go
type Stack []int
func (s *Stack) Push(v int) {
*s = append(*s, v) // O(1) amortized
}
func (s *Stack) Pop() int {
if len(*s) == 0 { return -1 }
index := len(*s) - 1
val := (*s)[index]
*s = (*s)[:index] // Shrink slice
return val
}
func (s *Stack) Peek() int {
if len(*s) == 0 { return -1 }
return (*s)[len(*s)-1]
}
[!NOTE] Java Specific: > [!WARNING] Do NOT use
java.util.Stack. It is a legacy class (synchronized, slow). Usejava.util.ArrayDequeinstead.
[!NOTE] Go Specific: In Go, we simply use a Slice.
3. The MinStack Problem (O(1) Min)
Challenge: Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
Naive Approach: Scan the stack for min? O(N). Too slow.
Optimal Approach: Use Two Stacks.
- Main Stack: Stores actual values.
- Min Stack: Stores the minimum value seen so far.
Interactive: MinStack Visualizer
Push values and watch how the MinStack updates.
Main Stack
Min Stack
Current Min: None
4. Implementation Details
Java
class MinStack {
private Deque<Integer> stack = new ArrayDeque<>();
private Deque<Integer> minStack = new ArrayDeque<>();
public void push(int val) {
stack.push(val);
// Only push to minStack if new value is <= current min
if (minStack.isEmpty() || val <= minStack.peek()) {
minStack.push(val);
}
}
public void pop() {
int val = stack.pop();
// Only pop minStack if we removed the min value
if (val == minStack.peek()) {
minStack.pop();
}
}
public int getMin() {
return minStack.peek();
}
}
Go
type MinStack struct {
stack []int
minStack []int
}
func (this *MinStack) Push(val int) {
this.stack = append(this.stack, val)
if len(this.minStack) == 0 || val <= this.minStack[len(this.minStack)-1] {
this.minStack = append(this.minStack, val)
}
}
func (this *MinStack) Pop() {
val := this.stack[len(this.stack)-1]
this.stack = this.stack[:len(this.stack)-1]
if val == this.minStack[len(this.minStack)-1] {
this.minStack = this.minStack[:len(this.minStack)-1]
}
}
func (this *MinStack) GetMin() int {
return this.minStack[len(this.minStack)-1]
}
Practice: Backspace String Compare
Apply your knowledge of LIFO for string processing: