Stack Fundamentals
Stack Fundamentals
A stack is a Last In First Out (LIFO) data structure. Think of a stack of plates - you can only add or remove from the top.
Core Operations
| Operation | Description | Time |
|---|---|---|
| push | Add element to top | O(1) |
| pop | Remove element from top | O(1) |
| peek/top | View top element | O(1) |
| isEmpty | Check if empty | O(1) |
Visual Example
push(1) → [1]
push(2) → [1, 2]
push(3) → [1, 2, 3]
peek() → returns 3
pop() → returns 3, stack becomes [1, 2]
Java Stack Implementation
// Using Java's built-in Stack
Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(2);
int top = stack.peek(); // 2
int val = stack.pop(); // 2
boolean empty = stack.isEmpty(); // false
// Using Deque (preferred in modern Java)
Deque<Integer> deque = new ArrayDeque<>();
deque.push(1); // or deque.addFirst(1)
deque.push(2);
int top = deque.peek(); // 2
int val = deque.pop(); // 2
Why Use Stack?
- Undo operations - text editors, browsers
- Function calls - recursion uses call stack
- Expression evaluation - postfix, infix
- Balanced parentheses - compiler syntax checking
- Depth-First Search - graph traversal
- Backtracking - maze solving, permutations
Stack Applications
Stack Applications
1. Balanced Parentheses (LeetCode 20)
public boolean isValid(String s) {
Deque<Character> stack = new ArrayDeque<>();
for (char c : s.toCharArray()) {
if (c == '(' || c == '[' || c == '{') {
stack.push(c);
} else {
if (stack.isEmpty()) return false;
char top = stack.pop();
if ((c == ')' && top != '(') ||
(c == ']' && top != '[') ||
(c == '}' && top != '{')) {
return false;
}
}
}
return stack.isEmpty();
}
// Time: O(n), Space: O(n)
2. Min Stack (LeetCode 155)
class MinStack {
Deque<Integer> stack;
Deque<Integer> minStack;
public MinStack() {
stack = new ArrayDeque<>();
minStack = new ArrayDeque<>();
}
public void push(int val) {
stack.push(val);
if (minStack.isEmpty() || val <= minStack.peek()) {
minStack.push(val);
}
}
public int pop() {
int val = stack.pop();
if (val == minStack.peek()) {
minStack.pop();
}
return val;
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}
3. Evaluate Reverse Polish Notation (LeetCode 150)
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new ArrayDeque<>();
for (String token : tokens) {
switch (token) {
case "+": stack.push(stack.pop() + stack.pop()); break;
case "-":
int b = stack.pop(), a = stack.pop();
stack.push(a - b);
break;
case "*": stack.push(stack.pop() * stack.pop()); break;
case "/":
b = stack.pop(); a = stack.pop();
stack.push(a / b);
break;
default: stack.push(Integer.parseInt(token));
}
}
return stack.pop();
}
4. Next Greater Element (LeetCode 496)
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
Map<Integer, Integer> map = new HashMap<>();
Deque<Integer> stack = new ArrayDeque<>();
for (int num : nums2) {
while (!stack.isEmpty() && stack.peek() < num) {
map.put(stack.pop(), num);
}
stack.push(num);
}
int[] result = new int[nums1.length];
for (int i = 0; i < nums1.length; i++) {
result[i] = map.getOrDefault(nums1[i], -1);
}
return result;
}
When to Use Stack
| Problem Type | Pattern |
|---|---|
| Balanced parentheses | Push open, pop on close |
| Next greater/smaller | Monotonic stack |
| Expression evaluation | Shunting yard |
| Undo operations | Push state, pop to undo |
| DFS traversal | Push neighbors |
Interactive Visualization
Stack Push/Pop Operations
Practice Problems
Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
Example:
Input: s = "()"
Output: true
Simple valid parentheses.
Optimal Solution — O(n) time, O(n) space
Stack to match opening and closing brackets
class Solution {
public boolean isValid(String s) {
Deque<Character> stack = new ArrayDeque<>();
for (char c : s.toCharArray()) {
if (c == '(' || c == '[' || c == '{') stack.push(c);
else {
if (stack.isEmpty()) return false;
char top = stack.pop();
if ((c == ')' && top != '(') || (c == ']' && top != '[') || (c == '}' && top != '{')) return false;
}
}
return stack.isEmpty();
}
}Edge Cases:
- Empty string
- Single character
- Only opening brackets
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
Example:
Input: push(-2), push(0), push(-3), getMin() → -3, pop(), top() → 0, getMin() → -2
Output: Operations work correctly
Min stack tracks minimum at each level.
Optimal Solution — O(1) for all operations time, O(n) space
Two stacks: main stack and min stack
class MinStack {
Deque<Integer> stack;
Deque<Integer> minStack;
public MinStack() {
stack = new ArrayDeque<>();
minStack = new ArrayDeque<>();
}
public void push(int val) {
stack.push(val);
if (minStack.isEmpty() || val <= minStack.peek()) {
minStack.push(val);
}
}
public int pop() {
int val = stack.pop();
if (val == minStack.peek()) minStack.pop();
return val;
}
public int top() { return stack.peek(); }
public int getMin() { return minStack.peek(); }
}Edge Cases:
- Pop minimum element
- Push duplicate minimum
- Single element
Given an array of integers temperatures, return an array answer such that answer[i] is the number of days you have to wait after the ith day to get a warmer temperature.
Example:
Input: temperatures = [73,74,75,71,69,72,76,73]
Output: [1,1,4,2,1,1,0,0]
Day 0 (73): wait 1 day for 74. Day 2 (75): wait 4 days for 76.
Optimal Solution — O(n) time, O(n) space
Monotonic stack: store indices, pop when warmer found
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int n = temperatures.length;
int[] answer = new int[n];
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) {
int prevIndex = stack.pop();
answer[prevIndex] = i - prevIndex;
}
stack.push(i);
}
return answer;
}
}Edge Cases:
- Already sorted ascending
- All same temperatures
- Single element
Given an array of integers heights representing the histogram's bar height, find the area of the largest rectangle in the histogram.
Example:
Input: heights = [2,1,5,6,2,3]
Output: 10
The largest rectangle is formed by bars at index 2 and 3 with height 5 and width 2.
Optimal Solution — O(n) time, O(n) space
Monotonic stack: find left and right boundaries for each bar
class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
Deque<Integer> stack = new ArrayDeque<>();
int maxArea = 0;
for (int i = 0; i <= n; i++) {
int h = (i == n) ? 0 : heights[i];
while (!stack.isEmpty() && h < heights[stack.peek()]) {
int height = heights[stack.pop()];
int width = stack.isEmpty() ? i : i - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
return maxArea;
}
}Edge Cases:
- Single bar
- Already sorted
- All same heights
Quiz
1. What principle does a stack follow?
2. What is the time complexity of push and pop operations?
3. What is the primary purpose of Stack?
4. What is a common mistake when implementing Stack?
Flashcards
Question
What is LIFO?
Click to reveal answer
Answer
Last In First Out - the most recently added element is removed first.
Question
When should I use a stack?
Click to reveal answer
Answer
For balanced parentheses, expression evaluation, undo operations, DFS, and backtracking.
Question
What is Stack?
Click to reveal answer
Answer
Stack is a key concept in software engineering.
Question
When to use Stack?
Click to reveal answer
Answer
Use Stack when building production systems that require reliability, scalability, and maintainability.
Question
Stack best practices
Click to reveal answer
Answer
Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.
Revision Notes
Key Takeaways
- 1.Stack is LIFO
- 2.All operations are O(1)
- 3.Use for balanced parentheses and expression evaluation
- 4.Deque is preferred over Stack class
Interview Tips
- •Always mention LIFO principle
- •Discuss when to use stack vs queue
- •Explain space complexity for nested structures
Cheat Sheet
Stack Cheat Sheet
Operations: push, pop, peek, isEmpty - all O(1)
Use Cases: Balanced parentheses, expression eval, undo, DFS
Java: Use Deque interface with ArrayDeque
Pattern: Push on open bracket, pop on close bracket