By Gopi Krishna Tummala
Introduction
This is your senior-engineer cheatsheet to Python interview mastery—the advanced patterns, time-savers, and “interview-flex” moves that appear in ~70% of medium/hard questions. These are the gotchas, one-liners, edge cases, and power moves that interviewers notice (and that save time under pressure).
Memorize the why behind each trick—that’s what gets the “Strong Hire” verdict.
1. Priority Queues / heapq (Very Common)
Python’s heapq is min-heap only. Interviewers expect you to know how to fake a max-heap and handle ties.
Max-Heap Trick (Most Common Interview Hack)
import heapq
maxh = []
heapq.heappush(maxh, -10)
heapq.heappush(maxh, -5)
largest = -heapq.heappop(maxh) # → 10
Why it works: Negating values turns a min-heap into a max-heap. The smallest negative number is the largest positive number.
Tuple Heap (Tie-Breaking)
# Heap of tuples compares FIRST element, then second, etc.
# Useful for (priority, timestamp, value)
heapq.heappush(heap, (priority, index, value))
# For max-heap with tuples → negate priority only
heapq.heappush(maxh, (-priority, index, value))
Gotcha: If objects are not comparable (like custom Nodes), always include an index or id in the tuple to avoid TypeError.
K Smallest / K Largest Patterns
# K largest → min-heap of size K (pop smallest to keep largest)
def kth_largest(nums, k):
heap = nums[:k]
heapq.heapify(heap) # O(k)
for num in nums[k:]:
if num > heap[0]:
heapq.heapreplace(heap, num) # pop + push in one O(log k)
return heap[0]
2. Dynamic Programming Hacks
@lru_cache — The “Pro” Way
from functools import lru_cache
@lru_cache(None) # None = unlimited cache
def dp(i, j):
if i < 0 or j < 0: return 0
# logic...
return dp(i-1, j) + dp(i, j-1)
Recursion Limit Hack
If you use DFS/Recursion on a large tree or grid, you must increase the limit or you’ll crash.
import sys
sys.setrecursionlimit(2000) # Default is usually 1000
Bottom-Up Space Optimization (Knapsack)
# 0/1 Knapsack → O(W) Space
dp = [0] * (W + 1)
for wt, val in items:
for w in range(W, wt - 1, -1): # REVERSE loop avoids using same item twice
dp[w] = max(dp[w], dp[w-wt] + val)
3. Union-Find (DSU) — The Silver Bullet
Essential for “Number of Provinces”, “Redundant Connection”, or any connectivity problem.
class DSU:
def __init__(self, n):
self.parent = list(range(n))
self.rank = [1] * n
def find(self, i):
if self.parent[i] == i:
return i
self.parent[i] = self.find(self.parent[i]) # Path Compression
return self.parent[i]
def union(self, i, j):
root_i, root_j = self.find(i), self.find(j)
if root_i != root_j:
# Union by Rank
if self.rank[root_i] > self.rank[root_j]:
self.parent[root_j] = root_i
elif self.rank[root_i] < self.rank[root_j]:
self.parent[root_i] = root_j
else:
self.parent[root_j] = root_i
self.rank[root_i] += 1
return True
return False
4. Trie (Prefix Tree) Template
For “Word Search II”, “Prefix Matches”, or “Autocomplete”.
class TrieNode:
def __init__(self):
self.children = {}
self.is_word = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word: str):
node = self.root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_word = True
Interview Flex: Use a dictionary of dictionaries root = {} for a 5-line Trie implementation if speed is prioritized.
5. Linked Lists: Fast & Slow Pointers
The standard for cycle detection and finding midpoints.
# Middle of List
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# slow is now at the middle (n//2)
# Cycle Detection (Floyd's)
if slow == fast: # they met!
6. Itertools Mastery (The “Cheating” Library)
Python’s itertools can solve “Combinations/Permutations” problems in one line.
from itertools import combinations, permutations, product, groupby
# All pairs: combinations([1,2,3], 2) -> (1,2), (1,3), (2,3)
# Cartesian Product: product([1,2], [a,b]) -> (1,a), (1,b), (2,a), (2,b)
# Group consecutive: [(k, list(g)) for k, g in groupby("AAAABBBCC")]
7. Advanced Bitwise Operations
| Operation | Syntax | Purpose |
|---|---|---|
| Check Power of 2 | n > 0 and n & (n-1) == 0 | Powers of 2 have 1 bit set |
| Get Last Set Bit | n & -n | Isolates the rightmost 1-bit |
| Clear Last Set Bit | n & (n-1) | Removes rightmost 1-bit |
| XOR Trick | a ^ a = 0 | Find the “single” number in pairs |
8. Binary Search Patterns
Search for Value
import bisect
idx = bisect.bisect_left(arr, target) # First index where x could be inserted
Search on Answer (Maximize/Minimize)
def check(mid):
# returns True if mid satisfies condition
pass
low, high = min_possible, max_possible
ans = high
while low <= high:
mid = (low + high) // 2
if check(mid):
ans = mid
high = mid - 1 # Try smaller for minimization
else:
low = mid + 1
9. Python Gotchas (The “Trap” Questions)
🚨 Mutable Default Arguments
def append_to(element, to=[]): # 'to' is created ONCE at definition time
to.append(element)
return to
print(append_to(1)) # [1]
print(append_to(2)) # [1, 2] !!!
Fix: Use to=None and set to = [] inside the function.
🚨 List Multiplication Shares References
grid = [[0]*3]*3
grid[0][0] = 1
# [[1, 0, 0], [1, 0, 0], [1, 0, 0]] !!!
Fix: grid = [[0]*3 for _ in range(3)]
10. Interview-Flex Syntax
Type Hinting (Looks Senior)
def solve(nums: list[int], target: int) -> int:
...
Walrus Operator (Assignment Expression)
if (n := len(nums)) > 10:
print(f"Processing large list of size {n}")
Sorted with Multi-Key
# Sort by length (desc), then alphabetically (asc)
words.sort(key=lambda x: (-len(x), x))
11. Performance Micro-Optimizations
| Slow | Fast | Why? |
|---|---|---|
if x in my_list | if x in my_set | O(n) vs O(1) |
list.pop(0) | deque.popleft() | O(n) vs O(1) |
s = s + char | "".join(list) | O(n²) vs O(n) |
a, b = b, a | temp = a; a = b... | Python’s swap is highly optimized |
12. Math & Geometry Essentials
- Ceil Division:
(a + b - 1) // b - Floating Point Comparison:
math.isclose(a, b)(Never use==for floats) - GCD/LCM:
math.gcd(a, b),math.lcm(a, b)(Py 3.9+) - Infinite:
float('inf'),float('-inf')
Conclusion: What Separates “Pass” vs “Strong Hire”
- Complexity Analysis: Don’t just give the answer; explain why it’s and not .
- Edge Cases: Mention empty inputs, single elements, and integer overflows (though Python handles large ints, mention it for “portability”).
- Clean Abstractions: Use
defaultdictinstead of manualif key not in dictchecks. - Naming:
slow/fastinstead ofi/jfor pointers.
Practice explaining the “Why” behind these hacks—that is what ultimately secures the offer. 🚀