Solve 10 classic queue interview problems — BFS shortest path, walls and gates, rotten oranges, number of islands, snake and ladder, sliding window maximum, first non-repeating character in stream, generate binary numbers, interleave queue halves, and LRU cache.
Problem 1 — Rotten Oranges (Multi-Source BFS)
Problem: A grid where 0=empty, 1=fresh orange, 2=rotten orange. Every minute, each rotten orange infects adjacent fresh oranges. Return minimum minutes until all oranges rot, or -1 if impossible.
| [[2,1,1],[1,1,0],[0,1,1]] | 4 |
| [[2,1,1],[0,1,1],[1,0,1]] | -1 (bottom-left isolated) |
| [[0,2]] | 0 (no fresh oranges) |
from collections import deque
def oranges_rotting(grid):
"""
Multi-source BFS from all initially rotten oranges simultaneously.
Time: O(m×n), Space: O(m×n)
"""
m, n = len(grid), len(grid[0])
queue = deque()
fresh_count = 0
# Initialize: find all rotten oranges and count fresh
for i in range(m):
for j in range(n):
if grid[i][j] == 2:
queue.append((i, j, 0)) # (row, col, time)
elif grid[i][j] == 1:
fresh_count += 1
if fresh_count == 0:
return 0 # No fresh oranges to rot
directions = [(0,1),(0,-1),(1,0),(-1,0)]
max_time = 0
while queue:
row, col, time = queue.popleft()
for dr, dc in directions:
r, c = row + dr, col + dc
if 0 <= r < m and 0 <= c < n and grid[r][c] == 1:
grid[r][c] = 2 # Infect
fresh_count -= 1
max_time = max(max_time, time + 1)
queue.append((r, c, time + 1))
return max_time if fresh_count == 0 else -1
print(oranges_rotting([[2,1,1],[1,1,0],[0,1,1]])) # 4
print(oranges_rotting([[2,1,1],[0,1,1],[1,0,1]])) # -1
Problem 3 — Snake and Ladder (BFS Shortest Path)
Problem: Given an n×n board with snakes and ladders, find minimum dice rolls to reach n².
from collections import deque
def snakes_and_ladders(board):
"""
BFS: each state = current cell. Find min moves to reach n².
Time: O(n²), Space: O(n²)
"""
n = len(board)
def cell_to_coord(s):
"""Convert cell number to board row, col."""
s -= 1 # 0-indexed
row = s // n
col = s % n
if row % 2 == 1:
col = n - 1 - col # Odd rows go right-to-left
return (n - 1 - row, col)
visited = {1}
queue = deque([(1, 0)]) # (cell, moves)
while queue:
cell, moves = queue.popleft()
for dice in range(1, 7):
next_cell = cell + dice
if next_cell > n * n:
break
r, c = cell_to_coord(next_cell)
if board[r][c] != -1:
next_cell = board[r][c] # Snake or ladder
if next_cell == n * n:
return moves + 1
if next_cell not in visited:
visited.add(next_cell)
queue.append((next_cell, moves + 1))
return -1 # Cannot reach end
Problem 4 — Word Ladder (BFS)
Problem: Given beginWord, endWord, and wordList, find shortest transformation sequence. Each step changes exactly one letter.
beginWord="hit", endWord="cog", wordList=["hot","dot","dog","lot","log","cog"]
→ 5 ("hit"→"hot"→"dot"→"dog"→"cog")
from collections import deque
def word_ladder(beginWord, endWord, wordList):
"""
BFS where each word is a node; edges connect words differing by 1 letter.
Time: O(M² × N) where M=word length, N=wordList size.
"""
word_set = set(wordList)
if endWord not in word_set:
return 0
queue = deque([(beginWord, 1)]) # (word, steps)
visited = {beginWord}
while queue:
word, steps = queue.popleft()
for i in range(len(word)):
for c in 'abcdefghijklmnopqrstuvwxyz':
new_word = word[:i] + c + word[i+1:]
if new_word == endWord:
return steps + 1
if new_word in word_set and new_word not in visited:
visited.add(new_word)
queue.append((new_word, steps + 1))
return 0
print(word_ladder("hit", "cog", ["hot","dot","dog","lot","log","cog"])) # 5
Problem 5 — First Non-Repeating Character in a Stream
Problem: For each character in a stream, print the first non-repeating character. Use '#' if none exists.
from collections import deque
def first_non_repeating(stream):
"""
Queue holds characters in order of appearance.
Hash map counts frequency of each character.
Front of queue = first non-repeating character.
Time: O(26n) = O(n), Space: O(26) = O(1)
"""
freq = {}
queue = deque()
result = []
for char in stream:
# Update frequency
freq[char] = freq.get(char, 0) + 1
# Add to queue
queue.append(char)
# Remove front elements that are now repeating
while queue and freq[queue[0]] > 1:
queue.popleft()
result.append(queue[0] if queue else '#')
return result
print(first_non_repeating("aabcbc")) # ['a', '#', 'b', 'b', 'c', 'c']
Problem 6 — Generate Binary Numbers 1 to N Using Queue
Problem: Generate binary representations of 1 to N in order using a queue.
N=5 → ["1","10","11","100","101"]
from collections import deque
def generate_binary_numbers(n):
"""
BFS: start with "1", generate children "10" and "11" by appending 0 and 1.
Time: O(n), Space: O(n)
"""
result = []
queue = deque(["1"])
while len(result) < n:
current = queue.popleft()
result.append(current)
queue.append(current + "0") # Left child
queue.append(current + "1") # Right child
return result
print(generate_binary_numbers(5)) # ['1', '10', '11', '100', '101']
print(generate_binary_numbers(7)) # ['1', '10', '11', '100', '101', '110', '111']
Problem 7 — Interleave First and Second Half of Queue
Problem: Given a queue of 2n elements, interleave first half with second half.
[1,2,3,4,5,6,7,8] → [1,5,2,6,3,7,4,8]
from collections import deque
def interleave_queue(queue):
"""
Use a stack to reverse first half, then interleave.
Time: O(n), Space: O(n/2)
"""
n = len(queue)
half = n // 2
# Step 1: Push first half to stack
stack = []
for _ in range(half):
stack.append(queue.popleft())
# Step 2: Enqueue stack elements back (reverses first half)
while stack:
queue.append(stack.pop())
# Step 3: Rotate second half to front
for _ in range(half):
queue.append(queue.popleft())
# Step 4: Interleave
while stack or len(queue) > 0:
if not stack:
for _ in range(half):
stack.append(queue.popleft())
queue.append(stack.pop())
queue.append(queue.popleft())
half -= 1
if half == 0:
break
return list(queue)
# Cleaner approach:
def interleave_queue_v2(arr):
"""Interleave using two-pointer."""
n = len(arr)
half = n // 2
result = []
for i in range(half):
result.append(arr[i])
result.append(arr[i + half])
return result
print(interleave_queue_v2([1,2,3,4,5,6,7,8])) # [1,5,2,6,3,7,4,8]
Problem 8 — Sliding Window Maximum Using Deque
Problem: Find maximum in each window of size k (covered in Deque lesson — key interview problem).
from collections import deque
def sliding_window_max(nums, k):
"""Monotonic decreasing deque. O(n), O(k)."""
result = []
dq = deque() # Indices
for i in range(len(nums)):
while dq and dq[0] < i - k + 1:
dq.popleft()
while dq and nums[dq[-1]] < nums[i]:
dq.pop()
dq.append(i)
if i >= k - 1:
result.append(nums[dq[0]])
return result
print(sliding_window_max([1,3,-1,-3,5,3,6,7], 3)) # [3,3,5,5,6,7]
Problem 9 — Design Hit Counter
Problem: Design a hit counter that counts hits in the last 5 minutes (300 seconds).
from collections import deque
class HitCounter:
"""
Queue stores timestamps of hits.
getHits removes timestamps older than 5 minutes before counting.
Time: O(1) amortized for hit, O(n) worst for getHits (but amortized O(1))
Space: O(n) where n = hits in last 5 minutes
"""
def __init__(self):
self._hits = deque()
def hit(self, timestamp: int) -> None:
"""Record a hit at timestamp."""
self._hits.append(timestamp)
def get_hits(self, timestamp: int) -> int:
"""Count hits in the last 5 minutes."""
cutoff = timestamp - 300 # Older than 5 minutes
while self._hits and self._hits[0] <= cutoff:
self._hits.popleft()
return len(self._hits)
# Testing:
hc = HitCounter()
hc.hit(1); hc.hit(2); hc.hit(3)
print(hc.get_hits(4)) # 3
hc.hit(300)
print(hc.get_hits(300)) # 4
print(hc.get_hits(301)) # 3 (hit at t=1 is outside 5-minute window)
Problem 10 — Perfect Squares (BFS Shortest Path)
Problem: Find the minimum number of perfect squares that sum to n.
n=12 → 3 (4+4+4)
n=13 → 2 (4+9)
from collections import deque
def num_squares(n):
"""
BFS: each level = one more perfect square added.
Find shortest path from 0 to n.
Time: O(n√n), Space: O(n)
"""
# Precompute perfect squares up to n
squares = []
i = 1
while i * i <= n:
squares.append(i * i)
i += 1
queue = deque([0])
visited = {0}
steps = 0
while queue:
steps += 1
for _ in range(len(queue)):
curr = queue.popleft()
for sq in squares:
next_val = curr + sq
if next_val == n:
return steps
if next_val < n and next_val not in visited:
visited.add(next_val)
queue.append(next_val)
return steps
print(num_squares(12)) # 3
print(num_squares(13)) # 2
Pattern Summary
| Problem | Queue Type | Pattern |
|---|
| Rotten Oranges | Regular queue | Multi-source BFS |
| Walls and Gates | Regular queue | Multi-source BFS |
| Snake and Ladder | Regular queue | BFS on state space |
| Word Ladder | Regular queue | BFS on implicit graph |
| First Non-Repeating | Queue + Hash Map | Stream processing |
| Generate Binary Numbers | Regular queue | BFS generation |
| Sliding Window Maximum | Monotonic deque | Maintain monotonic front |
| Hit Counter | Queue (deque) | Sliding window with timestamps |
| Perfect Squares | Regular queue | BFS for min steps |
The unifying pattern: Any problem asking for "minimum steps" or "shortest path" in an unweighted state space → BFS → Queue.
*Queues folder complete. Next: Recursion*