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_len

Pattern 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_water

Pattern 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
Display Options
Appearance
Text Size
100%