Day 2 · Topic 2
Stack
LIFO structure for problems requiring undo/redo, matching pairs, or tracking the nearest greater/smaller element. Monotonic stacks solve a class of "next greater element" problems in O(n).
// Monotonic Stack Pattern
Maintain elements in increasing or decreasing order. Pop when current element breaks the order — the popped element's "next greater/smaller" is the current element.
Easy Valid Parentheses
INSIGHT: Push open brackets. On close bracket, check if top of stack matches. If not → invalid.
def isValid(s):
stack = []
pairs = {')': '(', ']': '[', '}': '{'}
for c in s:
if c in '([{':
stack.append(c)
else:
if not stack or stack[-1] != pairs[c]:
return False
stack.pop()
return len(stack) == 0
# Time: O(n) | Space: O(n) Medium Min Stack
INSIGHT: Maintain a parallel min_stack that records the current minimum at each push. They stay in sync.
class MinStack:
def __init__(self):
self.stack = []
self.min_stack = []
def push(self, val):
self.stack.append(val)
min_val = min(val, self.min_stack[-1] if self.min_stack else val)
self.min_stack.append(min_val)
def pop(self):
self.stack.pop(); self.min_stack.pop()
def top(self): return self.stack[-1]
def getMin(self): return self.min_stack[-1]
# All operations O(1) Medium Daily Temperatures
INSIGHT: Monotonic decreasing stack of indices. When we see a warmer temp, it resolves all colder temps in the stack.
def dailyTemperatures(temperatures):
stack = [] # monotonic decreasing (stores indices)
result = [0] * len(temperatures)
for i, temp in enumerate(temperatures):
while stack and temperatures[stack[-1]] < temp:
idx = stack.pop()
result[idx] = i - idx # days until warmer
stack.append(i)
return result
# Time: O(n) | Space: O(n) Hard Largest Rectangle in Histogram
INSIGHT: Monotonic increasing stack. When a shorter bar is encountered, pop taller bars — their max extent to the right is now determined. The popped bar's left extent = where it was first pushed.
def largestRectangleArea(heights):
stack = [] # (index, height) — monotonic increasing
max_area = 0
for i, h in enumerate(heights):
start = i
while stack and stack[-1][1] > h:
idx, height = stack.pop()
max_area = max(max_area, height * (i - idx))
start = idx # can extend back to where popped bar started
stack.append((start, h))
for i, h in stack:
max_area = max(max_area, h * (len(heights) - i))
return max_area
# Time: O(n) | Space: O(n)