FAANG Interview Prep
Foundations, Memory & Complexity
Big-O notation, time/space analysis, memory layoutRecursion Complete Guide
Base cases, call stack, tail recursion, memoizationArrays & Array ADT
Static/dynamic arrays, operations, amortized analysisStrings
Pattern matching, string algorithms, encoding, manipulationMatrices
2D arrays, sparse matrices, matrix operations, traversalsLinked Lists
Singly, doubly, circular lists, pointer manipulationStack
LIFO, push/pop, expression evaluation, backtrackingQueue
FIFO, circular queue, deque, priority queueTrees
Binary trees, traversals, expression trees, threaded treesBST & Balanced Trees
Search, insert, delete, AVL, red-black, B-treesHeaps, Sorting & Hashing
Min/max heaps, heapsort, hash tables, collision handlingGraphs, DP, Greedy & Backtracking
BFS, DFS, shortest paths, dynamic programming, optimizationIntroduction to Queue
A queue is a linear data structure that follows the First-In-First-Out (FIFO) principle. Think of it like a line at a ticket counter - the first person to join the line is the first to be served. Queues are fundamental in computer science, used in process scheduling, BFS traversal, print spooling, and handling asynchronous data transfer.
Mental Model: The Queue
Problem it solves: Process items in the exact order they arrive — fairness, buffering, level-order traversal. FIFO guarantees the item waiting longest is served next.
When NOT to use: When priority matters (use min/max heap), when newest-first is needed (use stack), or when random access is required (use array or hash map).
Common misconception: "A Python list works fine as a queue." list.pop(0) is \(O(n)\) — it shifts all remaining elements. Use collections.deque for \(O(1)\) popleft. This mistake silently turns an \(O(n)\) BFS into \(O(n^{2})\).
Interview lens: BFS always uses a queue. Multi-source BFS (fire spreading, shortest distance from multiple starts simultaneously) is a queue problem many people miss. Monotonic deque enables sliding window maximum in \(O(n)\).
Production lens: Every message broker (RabbitMQ, AWS SQS, Kafka) is a distributed persistent queue. Thread pool executors hold task queues. Rate limiters use token bucket queues. Queue semantics are foundational to distributed systems design.
Queue Operations
Core Queue Operations
| Operation | Description | Time |
|---|---|---|
| enqueue(item) | Add item to rear | \(O(1)\) |
| dequeue() | Remove and return front item | \(O(1)\)* |
| front()/peek() | Return front item without removing | \(O(1)\) |
| isEmpty() | Check if queue is empty | \(O(1)\) |
| size() | Return number of items | \(O(1)\) |
* \(O(n)\) for simple array implementation due to shifting; \(O(1)\) for circular/linked list
Queue Implementations
Array-Based Queue (Simple)
The naive array-based queue stores elements in a list with front and rear indices. Enqueue appends at the rear (\(O(1)\)), but dequeue from the front requires shifting all remaining elements (\(O(n)\)). This is why simple arrays are a poor choice for queues — the circular queue (next section) fixes this by reusing vacated front space without shifting.
Linked List-Based Queue
A linked-list queue uses a front pointer for dequeue and a rear pointer for enqueue — giving true \(O(1)\) for both operations with no wasted space and no capacity limit. Enqueue creates a new node at rear; dequeue removes the node at front. This is the standard production implementation when you need an unbounded queue with guaranteed constant-time operations (used internally by Python's collections.deque).
Circular Queue
A circular queue (ring buffer) uses a fixed-size array where the rear wraps around to the front, making efficient use of space. Both enqueue and dequeue are \(O(1)\).
flowchart TD
E(["enqueue(x)"]) --> EC{"size == capacity?"}
EC -->|"Yes"| EF["QueueFull Error"]
EC -->|"No"| EG["rear = (rear + 1) % capacity\narr[rear] = x\nsize += 1"]
D(["dequeue()"]) --> DC{"size == 0?"}
DC -->|"Yes"| DF["QueueEmpty Error"]
DC -->|"No"| DG["val = arr[front]\nfront = (front + 1) % capacity\nsize -= 1\nreturn val"]
EG --> DONE1["O(1) ✓"]
DG --> DONE2["O(1) ✓"]
Deque (Double-Ended Queue)
A deque allows insertion and deletion at both ends, combining the capabilities of both stack and queue. Python's collections.deque is implemented as a doubly-linked list of fixed-size blocks, giving \(O(1)\) operations at both ends with good cache performance. Use a deque when you need both FIFO queue behavior AND the ability to push/pop from the front — for example, the "sliding window maximum" pattern or implementing a work-stealing scheduler.
Priority Queue
A priority queue serves elements based on their priority rather than insertion order. Unlike a regular queue (FIFO), the element with the highest priority (or lowest value in a min-priority queue) is always served first. Typically backed by a binary heap, giving \(O(\log n)\) insert and extract-min/max. Use cases: Dijkstra's shortest path, A* pathfinding, event-driven simulation, OS task scheduling (nice values), Huffman encoding, and any problem where you repeatedly need "the best/smallest/largest current option".
Queue Applications
Breadth-First Search (BFS)
BFS is the defining application of queues. The algorithm explores a graph level-by-level: visit all nodes at distance 1 from the source before any at distance 2. The queue maintains the "frontier" — nodes discovered but not yet explored. This level-by-level expansion naturally finds shortest paths in unweighted graphs and powers maze solvers, social network friend suggestions ("people 2 hops away"), and web crawlers.
Sliding Window Maximum (Monotonic Deque)
Given an array and window size \(k\), find the maximum in each window as it slides right. The brute force is \(O(nk)\). A monotonic decreasing deque solves it in \(O(n)\): the deque's front always holds the index of the current window's maximum. When sliding right: (1) remove indices that fell out of the window from the front, (2) remove all indices from the back whose values are smaller than the new element (they can never be the max), (3) add the new index. This is one of the most elegant deque applications in competitive programming.
Decision Lens: Queue Type Selection
| Need | Use | Key Method |
|---|---|---|
| Basic FIFO | collections.deque | append / popleft — both \(O(1)\) |
| Priority / min extraction | heapq or PriorityQueue | heappush / heappop — \(O(\log n)\) |
| Thread-safe queue | queue.Queue | Blocking put / get with timeout |
| Sliding window max/min | Monotonic deque | Maintain decreasing order, \(O(1)\) window max |
| Distributed / persistent | RabbitMQ / SQS / Kafka | AMQP / HTTP API; at-least-once delivery |
LeetCode Practice Problems
Easy 232. Implement Queue using Stacks
Implement a FIFO queue using only two stacks.
Medium 622. Design Circular Queue
Design a circular queue implementation.
Medium 102. Binary Tree Level Order Traversal
Return the level order traversal of a binary tree.
Hard 239. Sliding Window Maximum
Find the maximum in each sliding window.
Medium 621. Task Scheduler
Schedule tasks with cooldown period.
Quick Check — Test Yourself
- Implement a queue using two stacks. What are the amortized costs?
- Given a grid of 0s and 1s, find the shortest path from top-left to bottom-right using multi-source BFS.
- What is the sliding window maximum for
[1,3,-1,-3,5,3,6,7]with window size 3?
Common Bugs
- Using list.pop(0) for dequeue: This is \(O(n)\) in Python. Always use
collections.deque.popleft()for \(O(1)\). - Not marking visited in BFS: Marking visited when enqueuing (not when dequeuing) is critical — otherwise the same node gets added multiple times.
- Circular queue index wrap-around:
(rear + 1) % capacitynotrear + 1. Forgetting the modulo breaks the ring buffer.
Interview Lens
BFS problems often have non-obvious multi-source setups: “01 matrix” (distance from nearest 0), “rotting oranges” (simultaneous spread). The key insight: enqueue all sources at step 0 before starting BFS. This gives the correct shortest distance from any source in one pass.
Production Lens
AWS SQS, RabbitMQ, and Apache Kafka all implement queue semantics at distributed scale. Key concepts: at-least-once vs exactly-once delivery, dead-letter queues for failed messages, visibility timeout (message becomes invisible while being processed), and back-pressure when consumers are slower than producers.
Next in the Series
In Part 9: Trees & Tree Traversals, queues get their most important application — level-order (BFS) traversal is a queue in disguise, and trees are the foundation for BSTs, heaps, and tries.