Courses › Coding Interviews › Patterns
Stacks, Queues & Deques
Matching and nesting, expression evaluation, queues and the monotonic deque.
A stack is the right tool whenever the most recent unfinished thing must be handled first: matching brackets, nested structures, undo, and evaluating expressions. A queue handles things in arrival order: BFS, scheduling, and recent-event windows. A deque does both, and its monotonic form gives O(n) sliding-window maximums.
For "next greater element" problems, see Monotonic Stack.
In Python
Matching and nesting
Push openers. On a closer, the top of the stack must be its partner.
def is_valid(s):
pairs = {")": "(", "]": "[", "}": "{"}
stack = []
for ch in s:
if ch in pairs:
if not stack or stack.pop() != pairs[ch]:
return False
else:
stack.append(ch)
return not stackFor nested decoding like 3[a2[c]], push the current state (the string built so far and the repeat count) when you see [, and pop it to combine when you see ].
def decode_string(s):
stack, cur, num = [], "", 0
for ch in s:
if ch.isdigit():
num = num * 10 + int(ch)
elif ch == "[":
stack.append((cur, num))
cur, num = "", 0
elif ch == "]":
prev, k = stack.pop()
cur = prev + cur * k
else:
cur += ch
return curEvaluating expressions
Reverse Polish notation is the simplest case: push numbers, and on an operator pop two operands and push the result.
Infix with precedence (3+2*2, no parentheses): keep a stack of terms. Push +n and -n as they are, but apply * and / straight away to the top of the stack. The answer is the sum of the stack.
def calculate(s):
stack, num, op = [], 0, "+"
for i, ch in enumerate(s):
if ch.isdigit():
num = num * 10 + int(ch)
if ch in "+-*/" or i == len(s) - 1:
if op == "+": stack.append(num)
elif op == "-": stack.append(-num)
elif op == "*": stack.append(stack.pop() * num)
else: stack.append(int(stack.pop() / num)) # truncate toward 0
op, num = ch, 0
return sum(stack)With parentheses, push the running result and sign when you see (, and combine them when you see ). Or recurse on the inner expression.
Simulation with a stack
- Asteroid collision: the stack holds survivors. A left-moving asteroid fights the right-moving ones on top of the stack.
- Simplify a path: split on
/, push names, pop on.., ignore.and empty parts. - Exclusive time of functions: the stack holds the running function IDs. Charge the elapsed time to whichever function is on top.
Designing a stack with extras
Min stack: store (value, min_so_far) pairs so get_min is O(1). Max frequency stack: keep a map of value → count and a map of count → stack of values.
Queues and deques
- BFS: any shortest path in an unweighted graph or grid. See BFS & DFS.
- Recent-event windows: append timestamps and pop from the front while they're too old. This covers "hit counter" and "recent calls" problems.
- Circular queue: a fixed array with head and size indexes, using modulo arithmetic.
- Queue from two stacks: push onto
in. To pop, refilloutfrominonly whenoutis empty. Each element moves at most once, so operations are amortized O(1).
Monotonic deque: sliding window maximum
Keep the indexes in the deque with their values decreasing. A new value removes every smaller value from the back, because those values can never be the maximum again. The front is always the maximum of the current window.
from collections import deque
def max_sliding_window(nums, k):
dq, out = deque(), []
for i, x in enumerate(nums):
while dq and nums[dq[-1]] <= x:
dq.pop()
dq.append(i)
if dq[0] <= i - k: # front fell out of the window
dq.popleft()
if i >= k - 1:
out.append(nums[dq[0]])
return outThe same structure handles "longest subarray where max − min ≤ limit" (one deque for the maximum, one for the minimum) and "shortest subarray with sum ≥ k" with negative numbers (a monotonic deque over prefix sums).
[!TIP] Practice Valid Parentheses · Min Stack · Evaluate RPN · Decode String · Basic Calculator II · Asteroid Collision · Sliding Window Maximum · Design Hit Counter · Implement Queue Using Stacks