Skip to main content

Quick Interview Notes

Condensed revision notes for 12 key topics — scannable in minutes, covering the patterns, tricks, and templates that appear most in interviews.

📖 12 topics ⚡ Quick-scan format 💻 Code examples included
📋

Arrays & Hashing

3 min read

Practice →
  • › Two-pointer: use when array is sorted or needs O(1) space
  • › Sliding window: fixed/variable size subarray → O(n)
  • › HashMap for O(1) lookup: Two Sum, Group Anagrams, Top K Frequent
  • › Prefix sum: range queries in O(1) after O(n) preprocessing
  • › Kadane's algorithm: max subarray O(n) — track current vs global max
  • › Sort + binary search when O(n log n) is acceptable
Show code example ↓
# Sliding window — max sum subarray of size k
def max_sum(arr, k):
    win = sum(arr[:k])
    best = win
    for i in range(k, len(arr)):
        win += arr[i] - arr[i-k]
        best = max(best, win)
    return best
🔤

Strings

2 min read

  • › Anagram check: sort both or use Counter/frequency map
  • › Palindrome: two pointers from ends, or expand around center
  • › Trie: prefix search, autocomplete — O(m) per op where m = word length
  • › KMP / Rabin-Karp for substring search in O(n+m)
  • › String → int tricks: ord(c) - ord("a") for alphabet indexing
  • › Rolling hash for O(1) substring hashing in sliding windows
Show code example ↓
# Valid anagram — O(n)
from collections import Counter
def is_anagram(s, t):
    return Counter(s) == Counter(t)

# Expand around center — longest palindrome
def longest_palindrome(s):
    res = ""
    for i in range(len(s)):
        for l, r in [(i, i), (i, i+1)]:
            while l >= 0 and r < len(s) and s[l] == s[r]:
                if r - l + 1 > len(res):
                    res = s[l:r+1]
                l -= 1; r += 1
    return res
🌳

Trees & BST

4 min read

Practice →
  • › DFS (pre/in/post-order): use recursion or explicit stack
  • › BFS (level-order): use deque, process level by level
  • › BST property: left < node < right — use for O(log n) search
  • › Height of tree: max(height(left), height(right)) + 1
  • › Diameter: max path through any node = left_height + right_height
  • › Lowest Common Ancestor: if node is in both subtrees, it's the LCA
  • › Serialize/Deserialize: preorder + null markers
Show code example ↓
# Level-order traversal
from collections import deque
def level_order(root):
    if not root: return []
    result, q = [], deque([root])
    while q:
        level = []
        for _ in range(len(q)):
            node = q.popleft()
            level.append(node.val)
            if node.left:  q.append(node.left)
            if node.right: q.append(node.right)
        result.append(level)
    return result
🔗

Graphs

5 min read

Practice →
  • › BFS: shortest path in unweighted graph — use deque + visited set
  • › DFS: cycle detection, path finding, topological sort
  • › Union-Find (DSU): connected components, cycle detection in O(α(n))
  • › Dijkstra: weighted shortest path — min-heap + dist[] array — O((V+E) log V)
  • › Topological sort: DFS post-order or Kahn's BFS (in-degree)
  • › Grid as graph: 4-directional neighbors = edges
  • › Bipartite check: 2-color via BFS, fail if same color neighbors
Show code example ↓
# BFS shortest path
from collections import deque
def bfs(graph, src, dst):
    q = deque([(src, [src])])
    visited = {src}
    while q:
        node, path = q.popleft()
        if node == dst: return path
        for nb in graph[node]:
            if nb not in visited:
                visited.add(nb)
                q.append((nb, path + [nb]))
    return []
⚡

Dynamic Programming

6 min read

Practice →
  • › Identify: overlapping subproblems + optimal substructure
  • › Top-down (memoization): recursion + cache, easier to think
  • › Bottom-up (tabulation): fill table iteratively, better space
  • › 1D DP patterns: Fibonacci, Climbing Stairs, House Robber
  • › 2D DP patterns: LCS, Edit Distance, Knapsack, Coin Change
  • › State definition is everything — define dp[i] precisely
  • › Space optimization: often can reduce 2D table to 1D or 2 arrays
Show code example ↓
# Coin change — bottom up O(n*amount)
def coin_change(coins, amount):
    dp = [float('inf')] * (amount + 1)
    dp[0] = 0
    for a in range(1, amount + 1):
        for c in coins:
            if a >= c:
                dp[a] = min(dp[a], dp[a-c] + 1)
    return dp[amount] if dp[amount] != float('inf') else -1
📦

Heaps & Priority Queues

3 min read

  • › Min-heap: heapq in Python — always O(log n) push/pop
  • › Max-heap: negate values (Python has no built-in max-heap)
  • › Top K elements: use min-heap of size K — O(n log k)
  • › K closest points: max-heap of size K — pop when exceeds K
  • › Merge K sorted lists: min-heap of (val, list_idx, node_idx)
  • › Median of stream: two heaps (max-heap left + min-heap right)
Show code example ↓
import heapq

# Top K frequent elements
from collections import Counter
def top_k(nums, k):
    count = Counter(nums)
    return heapq.nlargest(k, count, key=count.get)

# Median of stream
class MedianFinder:
    def __init__(self):
        self.lo, self.hi = [], []  # max-heap, min-heap
    def addNum(self, num):
        heapq.heappush(self.lo, -num)
        heapq.heappush(self.hi, -heapq.heappop(self.lo))
        if len(self.hi) > len(self.lo):
            heapq.heappush(self.lo, -heapq.heappop(self.hi))
    def findMedian(self):
        if len(self.lo) > len(self.hi): return -self.lo[0]
        return (-self.lo[0] + self.hi[0]) / 2
🔄

Backtracking

4 min read

  • › Template: choose → explore → un-choose
  • › Permutations: swap[i] with each position, backtrack swap back
  • › Combinations/Subsets: include or exclude each element
  • › Constraint pruning early = massive time savings
  • › State = (current path, remaining choices, constraints)
  • › N-Queens: row by row, track cols/diagonals as sets
  • › Word search: DFS on grid, mark visited, unmark on backtrack
Show code example ↓
# Subsets — O(2^n)
def subsets(nums):
    result = []
    def bt(start, path):
        result.append(path[:])
        for i in range(start, len(nums)):
            path.append(nums[i])
            bt(i + 1, path)
            path.pop()
    bt(0, [])
    return result

# Permutations
def permute(nums):
    result = []
    def bt(path, remaining):
        if not remaining:
            result.append(path)
            return
        for i, n in enumerate(remaining):
            bt(path + [n], remaining[:i] + remaining[i+1:])
    bt([], nums)
    return result
🔗

Linked Lists

3 min read

  • › Two pointers: fast (×2) + slow (×1) for cycle, midpoint, nth-from-end
  • › Reverse: prev=None, curr=head, iterate swapping next pointers
  • › Merge two sorted lists: compare heads, recurse/iterate
  • › Detect cycle: Floyd's algorithm — fast meets slow inside cycle
  • › Find cycle start: after meet, reset one pointer to head
  • › Dummy head node: simplifies edge cases at list head
Show code example ↓
# Reverse linked list — iterative
def reverse(head):
    prev, curr = None, head
    while curr:
        nxt = curr.next
        curr.next = prev
        prev = curr
        curr = nxt
    return prev

# Find middle — slow/fast
def find_mid(head):
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    return slow
🏗

System Design Checklist

5 min read

Practice →
  • › 1. Clarify requirements: functional (what it does) + non-functional (scale, latency)
  • › 2. Estimate scale: QPS, storage (GB/TB/PB), bandwidth
  • › 3. High-level design: clients → load balancer → API servers → DB
  • › 4. Database choice: SQL (ACID, relations) vs NoSQL (scale, flexible schema)
  • › 5. Caching: Redis/Memcached — cache aside, write-through, TTL strategy
  • › 6. Message queue: Kafka/RabbitMQ for async, decoupling, fan-out
  • › 7. CDN: static assets, geo-distributed, edge caching
  • › 8. Deep dive: bottlenecks, failure modes, consistency vs availability
⏱

Time & Space Complexity

3 min read

Practice →
  • › O(1) — Hash map lookup, array index access
  • › O(log n) — Binary search, BST operations, balanced tree height
  • › O(n) — Linear scan, single pass, DFS/BFS on graph
  • › O(n log n) — Merge sort, heap sort, most efficient comparison sorts
  • › O(n²) — Nested loops, bubble/insertion sort, brute-force pairs
  • › O(2ⁿ) — Backtracking subsets, exponential recursion without memoization
  • › Space: recursion depth = O(h) for trees, O(n) for most DP tables
🎯

Behavioral (STAR Method)

4 min read

Practice →
  • › STAR: Situation → Task → Action → Result (with metrics)
  • › Prepare 8–10 stories covering: leadership, conflict, failure, success
  • › Amazon 16 LPs — know all of them: Customer Obsession, Ownership, Invent & Simplify...
  • › Meta: "Tell me about yourself" = 2-min pitch, not life story
  • › Google Googleyness: collaborative, thoughtful, honest about gaps
  • › Every story needs a measurable outcome: "reduced latency by 40%"
  • › "Why this company?" — research real products/teams, be specific

Ready to Practice?

These notes mean nothing without reps. Go apply them on real problems.

Buy me a coffee
Daily Practice
0/0