Pythonic Coding Interview Patterns: Standard Library Idioms & Algorithms
Solving algorithm and data structure coding interviews efficiently in Python requires leveraging Pythonβs built-in standard library utilities (collections, heapq, bisect, itertools). Senior candidates write clean, optimal, $O(N)$ Pythonic code using language idioms rather than re-inventing basic data structures from scratch.
This chapter details Pythonic coding interview patterns: defaultdict & Counter, heapq Min/Max heaps, bisect binary search, Sliding Window, Two Pointers, and Graph BFS/DFS traversal templates.
1. High-Yield Standard Library Data Structures
1. collections.Counter & defaultdict:
Eliminates verbose key existence checks:
from collections import Counter, defaultdict
# Frequency Counting in O(N)
counts = Counter("leetcode") # Counter({'e': 3, 'l': 1, 't': 1, 'c': 1, 'o': 1, 'd': 1})
top_2 = counts.most_common(2) # [('e', 3), ('l', 1)]
# Adjacency List for Graph Traversal
graph = defaultdict(list)
edges = [("A", "B"), ("A", "C"), ("B", "D")]
for u, v in edges:
graph[u].append(v) # Zero KeyError risk!2. Min-Heap & Max-Heap (heapq):
heapq implements a Min-Heap by default. For a Max-Heap, invert the numbers (-x):
import heapq
# Min-Heap (K Smallest Elements)
nums = [5, 1, 3, 9, 2]
heapq.heapify(nums) # In-place O(N) heap construction!
smallest = heapq.heappop(nums) # Returns 1 in O(log N)
# Max-Heap Pattern (Invert Numbers)
max_heap = [-x for x in [5, 1, 3, 9, 2]]
heapq.heapify(max_heap)
largest = -heapq.heappop(max_heap) # Returns 9!3. Binary Search (bisect):
bisect_left and bisect_right perform $O(\log N)$ binary search over sorted lists:
import bisect
sorted_nums = [10, 20, 30, 40, 50]
idx = bisect.bisect_left(sorted_nums, 30) # Returns index 2 in O(log N)!2. Core Algorithmic Coding Templates
Pattern 1: Sliding Window ($O(N)$ Time, $O(1)$ Space)
Find the longest substring without repeating characters:
def length_of_longest_substring(s: str) -> int:
char_map = {}
left = 0
max_len = 0
for right, char in enumerate(s):
if char in char_map and char_map[char] >= left:
left = char_map[char] + 1
char_map[char] = right
max_len = max(max_len, right - left + 1)
return max_lenPattern 2: Two Pointers (Container With Most Water - $O(N)$ Time)
def max_area(height: list[int]) -> int:
left, right = 0, len(height) - 1
max_water = 0
while left < right:
width = right - left
h = min(height[left], height[right])
max_water = max(max_water, width * h)
if height[left] < height[right]:
left += 1
else:
right -= 1
return max_waterPattern 3: Graph BFS Traversal (collections.deque - $O(V + E)$ Time)
from collections import deque
def bfs_shortest_path(graph: dict, start: str, target: str) -> int:
queue = deque([(start, 0)]) # (node, distance)
visited = {start}
while queue:
node, dist = queue.popleft()
if node == target:
return dist
for neighbor in graph[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append((neighbor, dist + 1))
return -1