F6 Stack vs queue: LIFO vs FIFO decision

Stack = most recent first (nesting, matching). Queue = oldest first (BFS, scheduling). Deque = both ends.

STACK (LIFO) vs QUEUE (FIFO)
────────────────────────────
STACK — Last In, First Out:
  "most recent" / "nested" / "matching"
  □ Parentheses matching
  □ Undo/redo
  □ DFS traversal (explicit stack)
  □ Monotonic stack (next greater element)
  □ Expression evaluation
  □ Call stack simulation

QUEUE — First In, First Out:
  "earliest" / "level-by-level" / "waiting line"
  □ BFS traversal (shortest path)
  □ Level-order tree traversal
  □ Task scheduling (FIFO order)
  □ Sliding window max (deque)
  □ Rate limiting (timestamp queue)

DEQUE — both ends:
  □ Sliding window maximum
  □ BFS optimizations
  □ Palindrome check

PRIORITY QUEUE (heap):
  □ "Next best" / "top K" / "median"
  □ Dijkstra, merge K sorted lists
F7 When to use monotonic stack

Monotonic stack finds nearest greater/smaller in O(n). The key insight: popping means we found the answer for that element.

WHEN TO USE MONOTONIC STACK
───────────────────────────
SIGNAL PHRASES:
  "next greater/smaller element"
  "previous greater/smaller element"
  "span" / "days until warmer"
  "largest rectangle in histogram"
  "stock span problem"

PATTERN:
  stack = []  # stores indices, monotonic order
  for i in range(n):
      while stack and a[stack[-1]] < a[i]:  # or >
          j = stack.pop()
          # a[j]'s next greater is a[i]
          # a[j]'s previous greater is stack[-1] (if exists)
      stack.append(i)

MONOTONIC INCREASING STACK: finds next smaller
MONOTONIC DECREASING STACK: finds next greater

WHEN NOT monotonic stack:
  × Sliding window max → use deque (not just stack)
  × Need both prev AND next → two passes or one pass
  × No "nearest" relationship → wrong tool

COMPLEXITY: O(n) — each element pushed and popped once