Stacks and queues are fundamental linear data structures that appear in countless LeetCode problems, from simple parentheses matching to complex monotonic stack optimizations. While conceptually simple — stacks follow LIFO (Last In First Out) and queues follow FIFO (First In First Out)— their applications span expression evaluation, graph traversal, sliding window optimizations, and priority-based processing. This comprehensive guide walks through stack fundamentals, classic applications (valid parentheses, min stack, RPN evaluation, daily temperatures), advanced monotonic stack techniques (next greater element, largest rectangle), queue-based BFS, priority queues for top-K problems, deque optimizations for sliding windows, and the classic "implement queue using stacks" puzzle. We'll cover time/space complexity analysis, common pitfalls, and practical interview strategies.
Series Navigation
📚 LeetCode Algorithm Masterclass Series (10 Parts): 1. Hash Tables (Two Sum, Longest Consecutive, Group Anagrams) 2. Two Pointers Techniques (Collision pointers, fast-slow, sliding window) 3. Linked List Operations (Reverse, cycle detection, merge) 4. Binary Tree Traversal & Recursion (Inorder/Preorder/Postorder, LCA) 5. Dynamic Programming Intro (1D/2D DP, state transition) 6. Backtracking Algorithms (Permutations, combinations, pruning) 7. Binary Search Advanced (Integer/Real binary search, answer binary search) 8. → Stack & Queue (Monotonic stack, priority queue, deque) ← You are here 9. Graph Algorithms (BFS/DFS, topological sort, union-find) 10. Greedy & Bit Manipulation (Greedy strategies, bitwise tricks)
Stack Fundamentals
What is a Stack?
A stack is a linear data structure that follows the LIFO (Last In First Out) principle. Think of it like a stack of plates: you add plates to the top and remove them from the top. The last plate added is the first one removed.
Core Operations
push(x): Add elementxto the top of the stackpop(): Remove and return the top elementpeek()ortop(): Return the top element without removing itisEmpty(): Check if the stack is emptysize(): Return the number of elements
Time Complexity
- All operations:
average and worst-case
Space Complexity
-
Implementation
Python: 1
2
3
4
5
6# Using list (append/pop from end)
stack = []
stack.append(1) # push
top = stack[-1] # peek
val = stack.pop() # pop
is_empty = len(stack) == 0
Java: 1
2
3
4
5Stack<Integer> stack = new Stack<>();
stack.push(1);
int top = stack.peek();
int val = stack.pop();
boolean isEmpty = stack.isEmpty();
C++: 1
2
3
4
5
6
stack<int> st;
st.push(1);
int top = st.top();
st.pop();
bool isEmpty = st.empty();
Queue Fundamentals
What is a Queue?
A queue is a linear data structure that follows the FIFO (First In First Out) principle. Think of it like a line at a store: the first person in line is the first person served.
Core Operations
enqueue(x)oroffer(x): Add elementxto the rear/backdequeue()orpoll(): Remove and return the front elementpeek()orfront(): Return the front element without removing itisEmpty(): Check if the queue is emptysize(): Return the number of elements
Time Complexity
- All operations:
average and worst-case (with proper implementation)
Space Complexity
-
Implementation
Python: 1
2
3
4
5
6from collections import deque
queue = deque()
queue.append(1) # enqueue
front = queue[0] # peek
val = queue.popleft() # dequeue
is_empty = len(queue) == 0
Java: 1
2
3
4
5Queue<Integer> queue = new LinkedList<>();
queue.offer(1);
int front = queue.peek();
int val = queue.poll();
boolean isEmpty = queue.isEmpty();
C++: 1
2
3
4
5
6
queue<int> q;
q.push(1);
int front = q.front();
q.pop();
bool isEmpty = q.empty();
Classic Stack Applications
LeetCode 20: Valid Parentheses
Problem Statement
Given a string s containing just the characters
'(', ')', '{', '}',
'[' and ']', determine if the input string is
valid.
An input string is valid if: 1. Open brackets must be closed by the same type of brackets 2. Open brackets must be closed in the correct order 3. Every close bracket has a corresponding open bracket of the same type
Example 1:
- Input:
s = "()" - Output:
true
Example 2:
- Input:
s = "()[]{}" - Output:
true
Example 3:
- Input:
s = "(]" - Output:
false
Example 4:
- Input:
s = "([)]" - Output:
false
Intuition
The key insight is that when we encounter a closing bracket, it must match the most recently opened bracket. This is exactly what a stack provides: we push opening brackets and pop when we see a matching closing bracket.
Algorithm
Initialize an empty stack
Iterate through each character in the string:
- If it's an opening bracket
(,[, or{, push it onto the stack - If it's a closing bracket
),], or}, check if the stack is empty or if the top doesn't match - If it matches, pop from the stack; otherwise, return
false
- If it's an opening bracket
After processing all characters, return
trueonly if the stack is empty
Solution
1 | def isValid(s: str) -> bool: |
Algorithm Visualization: The animation below demonstrates how the stack validates bracket matching:

Complexity Analysis
- Time Complexity:
where is the length of the string. We traverse the string once. - Space Complexity:
in the worst case when all characters are opening brackets.
Edge Cases
- Empty string: Should return
true - Single character: Should return
false - Only opening brackets: Stack won't be empty, return
false - Only closing brackets: Stack will be empty when checking, return
false
LeetCode 155: Min Stack
Problem Statement
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
Implement the MinStack class:
MinStack()initializes the stack objectvoid push(int val)pushes the elementvalonto the stackvoid pop()removes the element on the top of the stackint top()gets the top element of the stackint getMin()retrieves the minimum element in the stack
Example: 1
2
3
4
5
6Input:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
Output:
[null,null,null,null,-3,null,0,-2]
Intuition
The challenge is maintaining the minimum element while allowing normal stack operations. We need to track the minimum at each level of the stack, not just the global minimum.
Approach 1: Two Stacks
Maintain two stacks: one for values and one for minimums.
1 | class MinStack: |
Approach 2: Single Stack with Pairs
Store pairs of (value, min_so_far) in a single
stack.
1 | class MinStack: |
Complexity Analysis
- Time Complexity: All operations are
- Space Complexity:
for both approaches
LeetCode 150: Evaluate Reverse Polish Notation
Problem Statement
Evaluate the value of an arithmetic expression in Reverse Polish Notation (RPN).
Valid operators are +, -, *,
and /. Each operand may be an integer or another
expression.
Note: Division between two integers should truncate toward zero.
Example 1:
- Input:
tokens = ["2","1","+","3","*"] - Output:
9 - Explanation:
((2 + 1) * 3) = 9
Example 2:
- Input:
tokens = ["4","13","5","/","+"] - Output:
6 - Explanation:
(4 + (13 / 5)) = 6
Example 3:
- Input:
tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"] - Output:
22
Intuition
RPN (also called postfix notation) eliminates the need for parentheses. The algorithm is straightforward: 1. When we see a number, push it onto the stack 2. When we see an operator, pop the top two numbers, apply the operator, and push the result back
Solution
1 | def evalRPN(tokens: List[str]) -> int: |
Important Note on Division
The problem requires truncation toward zero. In Python,
int(a / b) handles this correctly for both positive and
negative numbers:
int(13 / 5) = 2int(-13 / 5) = -2
Complexity Analysis
- Time Complexity:
where is the number of tokens - Space Complexity:
in the worst case when all tokens are numbers
LeetCode 739: Daily Temperatures
Problem Statement
Given an array of integers temperatures representing the
daily temperatures, return an array answer such that
answer[i] is the number of days you have to wait after
theanswer[i] == 0 instead.
Example 1:
- Input:
temperatures = [73,74,75,71,69,72,76,73] - Output:
[1,1,4,2,1,1,0,0]
Example 2:
- Input:
temperatures = [30,40,50,60] - Output:
[1,1,1,0]
Example 3:
- Input:
temperatures = [30,60,90] - Output:
[1,1,0]
Intuition
For each day, we need to find the next greater element. This is a classic monotonic stack problem. We maintain a stack of indices where temperatures are in decreasing order. When we find a warmer day, we can resolve all previous colder days.
Solution
1 | def dailyTemperatures(temperatures: List[int]) -> List[int]: |
Walkthrough
For temperatures = [73,74,75,71,69,72,76,73]:
i=0, temp=73: Stack[0]i=1, temp=74:74 > 73, pop0,answer[0]=1, Stack[1]i=2, temp=75:75 > 74, pop1,answer[1]=1, Stack[2]i=3, temp=71:71 < 75, Stack[2,3]i=4, temp=69:69 < 71, Stack[2,3,4]i=5, temp=72:72 > 69, pop4,answer[4]=1;72 > 71, pop3,answer[3]=2; Stack[2,5]i=6, temp=76:76 > 72, pop5,answer[5]=1;76 > 75, pop2,answer[2]=4; Stack[6]i=7, temp=73:73 < 76, Stack[6,7]
Result: [1,1,4,2,1,1,0,0]
Complexity Analysis
- Time Complexity:
- each element is pushed and popped at most once
- Space Complexity:
for the stack
Monotonic Stack
A monotonic stack is a stack where elements are in either strictly increasing or strictly decreasing order. It's incredibly powerful for problems involving "next greater/smaller element" patterns.
Key Pattern
Monotonic stacks help solve problems where you need to find:
- Next greater element
- Next smaller element
- Previous greater element
- Previous smaller element
LeetCode 496: Next Greater Element I
Problem Statement
The next greater element of some element
x in an array is the first greater element
that is to the right of x in the same
array.
You are given two distinct 0-indexed integer arrays
nums1 and nums2, where nums1 is a
subset of nums2.
For each 0 <= i < nums1.length, find the index
j such that nums1[i] == nums2[j] and determine
the next greater element of nums2[j] in
nums2. If there is no next greater element, then the answer
for this query is -1.
Return an array ans of length nums1.length
such that ans[i] is the next greater element as described
above.
Example 1:
- Input:
nums1 = [4,1,2],nums2 = [1,3,4,2] - Output:
[-1,3,-1] - Explanation: The next greater element for each value of
nums1is as follows:- 4 is underlined in
nums2 = [1,3,4,2]. There is no next greater element, so the answer is -1. - 1 is underlined in
nums2 = [1,3,4,2]. The next greater element is 3. - 2 is underlined in
nums2 = [1,3,4,2]. There is no next greater element, so the answer is -1.
- 4 is underlined in
Solution
1 | def nextGreaterElement(nums1: List[int], nums2: List[int]) -> List[int]: |
Complexity Analysis
- Time Complexity:
where is nums1.lengthandis nums2.length - Space Complexity:
for the stack and map
LeetCode 84: Largest Rectangle in Histogram
Problem Statement
Given an array of integers heights representing the
histogram's bar height where the width of each bar is 1, return the area
of the largest rectangle in the histogram.
Example:
- Input:
heights = [2,1,5,6,2,3] - Output:
10 - Explanation: The largest rectangle is formed by bars at indices 2
and 3 (heights 5 and 6), area =
Intuition
For each bar, the largest rectangle that includes it extends as far
left and right as possible while maintaining height
- Left boundary: first bar to the left that's shorter
- Right boundary: first bar to the right that's shorter
A monotonic stack helps us find these boundaries efficiently.
Solution
1 | def largestRectangleArea(heights: List[int]) -> int: |
Walkthrough
For heights = [2,1,5,6,2,3]:
i=0, h=2: Stack[0]i=1, h=1:1 < 2, pop0, width=1-0=1, area=2*1=2, Stack[1]i=2, h=5: Stack[1,2]i=3, h=6: Stack[1,2,3]i=4, h=2:2 < 6, pop3, width=4-2-1=1, area=6*1=6;2 < 5, pop2, width=4-1-1=2, area=5*2=10; Stack[1,4]i=5, h=3: Stack[1,4,5]- Process remaining: pop
5, width=6-4-1=1, area=3*1=3; pop4, width=6-1-1=4, area=2*4=8; pop1, width=6, area=1*6=6
Maximum: 10
Complexity Analysis
- Time Complexity:
- each bar is pushed and popped once
- Space Complexity:
for the stack
Queue and BFS
Queues are essential for Breadth-First Search (BFS) algorithms, which explore nodes level by level.
BFS Pattern
1 | from collections import deque |
LeetCode 102: Binary Tree Level Order Traversal
Problem Statement
Given the root of a binary tree, return the level order traversal of its nodes' values (i.e., from left to right, level by level).
Example:
- Input:
root = [3,9,20,null,null,15,7] - Output:
[[3],[9,20],[15,7]]
Solution
1 | def levelOrder(root: Optional[TreeNode]) -> List[List[int]]: |
Complexity Analysis
- Time Complexity:
where is the number of nodes - Space Complexity:
for the queue
Priority Queue and Heap
A priority queue is an abstract data type where elements are served based on priority. In LeetCode, it's typically implemented using a heap.
Heap Operations
- Insert:
- Extract min/max:
- Peek:
LeetCode 347: Top K Frequent Elements
Problem Statement
Given an integer array nums and an integer
k, return the k most frequent elements. You
may return the answer in any order.
Example 1:
- Input:
nums = [1,1,1,2,2,3],k = 2 - Output:
[1,2]
Example 2:
- Input:
nums = [1],k = 1 - Output:
[1]
Approach 1: Min Heap (Size K)
Maintain a min-heap of size k containing the most
frequent elements.
1 | import heapq |
Approach 2: Max Heap (All Elements)
Use a max-heap and pop k times.
1 | def topKFrequent(nums: List[int], k: int) -> List[int]: |
Approach 3: Bucket Sort
Since frequencies are bounded by array length, we can use bucket sort
for
1 | def topKFrequent(nums: List[int], k: int) -> List[int]: |
Complexity Analysis
- Approach 1:
time, space - Approach 2:
time, space - Approach 3:
time, space
Deque (Double-Ended Queue)
A deque allows insertion and deletion from both ends
in
LeetCode 239: Sliding Window Maximum
Problem Statement
You are given an array of integers nums, there is a
sliding window of size k which is moving from the very left
of the array to the very right. You can only see the k
numbers in the window. Each time the sliding window moves right by one
position. Return the maximum element in each window.
Example:
- Input:
nums = [1,3,-1,-3,5,3,6,7],k = 3 - Output:
[3,3,5,5,6,7] - Explanation:
- Window position:
[1 3 -1] -3 5 3 6 7, max = 3 - Window position:
1 [3 -1 -3] 5 3 6 7, max = 3 - Window position:
1 3 [-1 -3 5] 3 6 7, max = 5 - Window position:
1 3 -1 [-3 5 3] 6 7, max = 5 - Window position:
1 3 -1 -3 [5 3 6] 7, max = 6 - Window position:
1 3 -1 -3 5 [3 6 7], max = 7
- Window position:
Intuition
We maintain a deque that stores indices in decreasing order of their values. The front always contains the index of the maximum element in the current window.
Solution
1 | from collections import deque |
Walkthrough
For nums = [1,3,-1,-3,5,3,6,7], k = 3:
i=0, val=1: DQ[0]i=1, val=3: Remove0(3 > 1), DQ[1]i=2, val=-1: DQ[1,2], result[3](window complete)i=3, val=-3: DQ[1,2,3], result[3,3]i=4, val=5: Remove3,2,1(5 > all), DQ[4], result[3,3,5]i=5, val=3: DQ[4,5], result[3,3,5,5]i=6, val=6: Remove5(6 > 3), DQ[4,6], but4is out of window, remove it, DQ[6], result[3,3,5,5,6]i=7, val=7: Remove6(7 > 6), DQ[7], result[3,3,5,5,6,7]
Complexity Analysis
- Time Complexity:
- each element is added and removed at most once
- Space Complexity:
for the deque
LeetCode 232: Implement Queue using Stacks
Problem Statement
Implement a first-in-first-out (FIFO) queue using only two stacks.
The implemented queue should support all the functions of a normal queue
(push, peek, pop, and
empty).
Solution: Two Stacks Approach
Use one stack for input and one for output. When output is empty, transfer all elements from input to output.
1 | class MyQueue: |
Amortized Complexity
- Push:
- Pop/Peek: Amortized
(each element moved at most once) Space:
LeetCode 225: Implement Stack using Queues
Problem Statement
Implement a last-in-first-out (LIFO) stack using only two queues. The
implemented stack should support all the functions of a normal stack
(push, top, pop, and
empty).
Solution: Two Queues Approach
Use one main queue and one temporary queue. For push, add to main. For pop/top, move all but last element to temp, then swap.
1 | from collections import deque |
Alternative: Single Queue
1 | class MyStack: |
Complexity Analysis
- Push:
- need to rotate
elements - Pop/Top:
Space:
Complexity Analysis Summary
Stack Operations
| Operation | Time Complexity | Space Complexity |
|---|---|---|
| Push | ||
| Pop | ||
| Peek | ||
| Search |
Queue Operations
| Operation | Time Complexity | Space Complexity |
|---|---|---|
| Enqueue | ||
| Dequeue | ||
| Peek | ||
| Search |
Priority Queue (Heap) Operations
| Operation | Time Complexity | Space Complexity |
|---|---|---|
| Insert | ||
| Extract Min/Max | ||
| Peek | ||
| Build Heap |
Deque Operations
| Operation | Time Complexity | Space Complexity |
|---|---|---|
| Push Front/Back | ||
| Pop Front/Back | ||
| Peek Front/Back |
Common Patterns and Tips
When to Use Stack
- Matching problems: Parentheses, brackets, tags
- Next/Previous greater/smaller element: Monotonic stack
- Expression evaluation: RPN, infix to postfix
- DFS traversal: Implicit call stack or explicit stack
- Undo/Redo operations: History tracking
When to Use Queue
- BFS traversal: Level-order processing
- Sliding window: With deque for optimizations
- Task scheduling: Round-robin, priority queues
- Cache replacement: LRU cache (with hash map)
When to Use Monotonic Stack
- Next greater element: Decreasing stack
- Next smaller element: Increasing stack
- Largest rectangle: Find boundaries efficiently
- Trapping rainwater: Find left/right boundaries
When to Use Priority Queue
- Top K problems: Maintain heap of size K
- Merge K sorted lists: Compare heads efficiently
- Dijkstra's algorithm: Process nodes by distance
- Event scheduling: Process by time/priority
Q&A: Common Questions
Q1: Why use a deque instead of a list for queues in Python?
A: Python's list haspop(0) (removing from front), while
deque.popleft() isdeque.
Q2: What's the difference between a stack and a queue?
A: Stack is LIFO (Last In First Out) - like a stack of plates. Queue is FIFO (First In First Out) - like a line at a store. The removal order is opposite.
Q3: Can I implement a stack using only one queue?
A: Yes, but push becomes
Q4: When should I use a monotonic stack vs. a regular stack?
A: Use monotonic stack when you need to find "next greater/smaller element" patterns. Regular stack is fine for matching, expression evaluation, and DFS.
Q5: What's the space complexity of a recursive DFS vs. iterative DFS with stack?
A: Both are
Q6: How do I choose between min-heap and max-heap for top-K problems?
A: For "top K largest", use min-heap of size K
(remove smallest). For "top K smallest", use max-heap of size K (remove
largest). In Python, use negative values for max-heap behavior with
heapq.
Q7: Why
is the sliding window maximum solution not ?
A: Each element is added to deque once and removed
at most once. Even though we have nested loops, the total operations are
bounded by
Q8: Can I use a stack for BFS?
A: Technically yes, but it would give DFS behavior (LIFO). BFS requires FIFO, so use a queue. Stack + BFS = wrong algorithm.
Q9: What's the best way to implement a min-stack?
A: Two approaches: (1) Two stacks (values + mins),
(2) Single stack with pairs (value, min_so_far). Both
are
Q10: How do I handle division by zero in RPN evaluation?
A: Check if the divisor is zero before division. The problem usually guarantees valid input, but in interviews, mention this edge case.
Summary
Stacks and queues are deceptively simple data structures with powerful applications:
Key Takeaways
Stack (LIFO): Perfect for matching problems, expression evaluation, and monotonic stack optimizations
Queue (FIFO): Essential for BFS and level-order traversals
Monotonic Stack: Efficiently solves "next greater/smaller element" problems in
Priority Queue/Heap: Ideal for top-K problems and greedy algorithms
Deque: Optimizes sliding window problems with
operations on both ends
Problem Patterns
- Valid Parentheses: Stack for matching
- Min Stack: Maintain minimum at each level
- RPN Evaluation: Stack for operands
- Daily Temperatures: Monotonic stack for next greater
- Largest Rectangle: Monotonic stack for boundaries
- Level Order Traversal: Queue for BFS
- Top K Frequent: Priority queue or bucket sort
- Sliding Window Maximum: Deque for optimization
Interview Tips
- Recognize the pattern: matching → stack, level-order → queue, next greater → monotonic stack
- Watch for edge cases: empty stacks/queues, single elements, all same values
- Consider space-time tradeoffs: monotonic stack trades space for
time - Practice implementations: Queue using stacks, stack using queues
- Know your language: Python
deque, JavaPriorityQueue, C++priority_queue
Master these fundamentals, and you'll be well-equipped to tackle stack and queue problems in LeetCode interviews!
- Post title:LeetCode (10): Stack and Queue
- Post author:Chen Kai
- Create time:2023-08-20 00:00:00
- Post link:https://www.chenk.top/en/leetcode-stack-and-queue/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.