The standard library that wins coding rounds
collections, heapq, bisect, itertools, math and functools — the imports that turn thirty lines into five, plus fast input and the recursion limit.
Python's advantage in a timed coding round is not syntax. It is that a dozen things you would have to implement in Java or C++ are one import away, already correct and written in C.
These are the ones that actually come up.
collections
from collections import Counter, defaultdict, deque, namedtupleCounter — counting anything.
c = Counter("placement")
print(c["e"]) # 2
print(c.most_common(2)) # [('e', 2), ('p', 1)]
print(Counter("abc") == Counter("cba")) # True — anagram check, one line
# subtracting counters gives what is missing
print(Counter("aab") - Counter("ab")) # Counter({'a': 1})Anagram questions, character-frequency questions and "most frequent element" questions all reduce
to a Counter.
defaultdict — grouping without an if, covered in lesson 5.
deque — a double-ended queue with O(1) operations at both ends.
from collections import deque
q = deque([1, 2, 3])
q.append(4) # right
q.appendleft(0) # left, O(1) — a list would be O(n)
q.pop() # right
q.popleft() # left, O(1)
q.rotate(1) # rotate right
window = deque(maxlen=3) # bounded — pushing a 4th drops the oldestAny BFS is a deque. Any sliding-window-maximum question is a deque. Using a list and pop(0)
is the difference between passing and timing out on a large input.
namedtuple — a tuple with names, when a dataclass is more than you need.
from collections import namedtuple
Point = namedtuple("Point", "x y")
p = Point(3, 4)
print(p.x, p[0]) # 3 3heapq — a priority queue
Python has no PriorityQueue class you would want in a coding round; it has functions that treat
a plain list as a min-heap.
import heapq
heap = [5, 1, 3]
heapq.heapify(heap) # O(n), in place
heapq.heappush(heap, 2) # O(log n)
print(heapq.heappop(heap)) # 1 — always the SMALLEST, O(log n)
print(heap[0]) # peek without removing, O(1)
print(heapq.nsmallest(2, [5, 1, 3])) # [1, 3]
print(heapq.nlargest(2, [5, 1, 3])) # [5, 3]It is a min-heap only. For a max-heap, negate:
values = [5, 1, 3]
max_heap = [-v for v in values]
heapq.heapify(max_heap)
print(-heapq.heappop(max_heap)) # 5For "k largest / k smallest / k closest" questions, a heap of size k is O(n log k) and beats sorting the whole input. Push tuples to carry a payload — the first element is the priority:
heapq.heappush(heap, (distance, node))bisect — binary search on a sorted list
import bisect
xs = [1, 3, 5, 7]
print(bisect.bisect_left(xs, 5)) # 2 — first index where 5 could go
print(bisect.bisect_right(xs, 5)) # 3 — after any existing 5s
bisect.insort(xs, 4) # insert keeping order
print(xs) # [1, 3, 4, 5, 7]Two real uses: checking membership in a sorted list in O(log n), and maintaining a sorted list as
values arrive. Note insort is O(n) — the search is logarithmic, the shift is not.
itertools
from itertools import (
permutations, combinations, product, accumulate,
groupby, chain, islice, count, cycle, repeat,
)
print(list(permutations([1, 2, 3], 2)))
# [(1,2), (1,3), (2,1), (2,3), (3,1), (3,2)] — order matters
print(list(combinations([1, 2, 3], 2)))
# [(1,2), (1,3), (2,3)] — order does not
print(list(product([0, 1], repeat=2)))
# [(0,0), (0,1), (1,0), (1,1)] — nested loops, flattened
print(list(accumulate([1, 2, 3, 4])))
# [1, 3, 6, 10] — running total / prefix sums
print(list(chain([1, 2], [3]))) # [1, 2, 3]
print(list(islice(count(10), 3))) # [10, 11, 12]accumulate gives prefix sums in one call, which is the backbone of range-sum questions.
product(..., repeat=n) replaces n nested loops when n is a variable.
A word of warning: permutations of 10 items is 3.6 million tuples. These are lazy, so generating
them is cheap; consuming all of them is not. If a question tempts you into permutations, check
the input size first — that is usually the point of the question.
functools
from functools import lru_cache, cache, reduce
@cache # Python 3.9+; use @lru_cache(maxsize=None) below that
def fib(n):
return n if n < 2 else fib(n - 1) + fib(n - 2)
print(fib(100)) # instant — without the cache this is 2^100 callsOne decorator turns exponential recursion into linear. Every memoisation question — fibonacci,
grid paths, coin change, stairs — is @cache plus the naive recursion. Be ready to also write the
dictionary by hand, because some interviewers ask for it:
def fib(n, memo={}): # dict default is safe here only because we never replace it
if n < 2:
return n
if n not in memo:
memo[n] = fib(n - 1, memo) + fib(n - 2, memo)
return memo[n]reduce folds a sequence into one value. Usually a loop or sum is clearer, but it appears in
questions about functional style:
from functools import reduce
print(reduce(lambda a, b: a * b, [1, 2, 3, 4])) # 24math, and integer maths
import math
math.gcd(12, 18) # 6
math.lcm(4, 6) # 12, Python 3.9+
math.isqrt(17) # 4 — exact integer square root, no float error
math.factorial(5) # 120
math.comb(5, 2) # 10
math.inf, -math.inf # sentinels for "no minimum yet"
math.floor(-1.5) # -2
math.ceil(1.2) # 2math.isqrt matters: int(n ** 0.5) goes through a float and can be off by one for large n,
which silently breaks a primality test. And math.inf is the right initial value for a
running-minimum, rather than picking a large number and hoping.
Reading input fast
In an online judge, input() called a hundred thousand times is slow enough to matter:
import sys
data = sys.stdin.read().split() # everything at once
n = int(data[0])
values = list(map(int, data[1:n + 1]))
# or, line by line but still buffered
input = sys.stdin.readline # rebind, then use input() as normalAnd output: one print per line is slow, so build and write once.
sys.stdout.write("\n".join(map(str, results)) + "\n")The recursion limit
Python's default recursion limit is 1000 frames. A recursive solution on an input of 10⁵ will
raise RecursionError even though the logic is right:
import sys
sys.setrecursionlimit(10 ** 6)Raise it when you must, and know the honest caveat: this raises Python's own guard, not the operating system's stack limit, so very deep recursion can still crash the process. Where you can, convert to an iterative solution with an explicit stack.
The eight-line cheat sheet
from collections import Counter, defaultdict, deque
import heapq, bisect, math, sys
from itertools import permutations, combinations, accumulate
from functools import cacheType that from memory before you start a coding round, and most of what you need is already there.
What to take into an interview
Counterfor frequencies and anagrams;defaultdictfor grouping;dequefor BFS and queues.heapqis a min-heap on a plain list. Negate for a max-heap. Size-k heap beats a full sort.bisectis binary search on a sorted list;insortkeeps it sorted but is O(n).itertools.accumulategives prefix sums;product(repeat=n)replaces n nested loops.@cacheturns naive recursion into memoised recursion in one line.math.isqrtavoids float error;math.infis the right "no value yet".sys.stdin.read()for large input;sys.setrecursionlimitfor deep recursion.