Coding Track

Coding Interview Workbook

Practice the habits that separate advanced coding rounds from memorized answers: invariants, edge tests, complexity proofs, debugging moves, and production follow-ups for speech and model-serving systems.

Interview Method

Say The Contract Before The Code

An experienced candidate makes the problem smaller before typing. Define input shape, output contract, invariant, failure cases, and the simplest test that can disprove the idea.

  1. Restate: name the data structure and clarify duplicates, order, mutability, and empty input.
  2. Choose: map the prompt to a pattern such as hash lookup, two pointers, heap, BFS, DFS, DP, or binary search.
  3. Prove: state the loop, recursion, or table invariant in one sentence.
  4. Code: keep helper functions small and avoid clever transformations that hide edge cases.
  5. Test: run the minimum set that covers empty, one item, duplicates, impossible states, and boundary values.
  6. Extend: answer the production follow-up about streaming data, memory, concurrency, privacy, or observability.
Question: What makes a coding answer advanced?

It is correct, readable, and testable, but it also explains why the invariant is sufficient, how the solution fails under changed constraints, and what telemetry or guardrails would be needed if the algorithm became part of a production speech or inference service.

Worked Drills

Write These Before Opening The Answers

Drill 1: Top K Frequent Words

Given a list of words and an integer k, return the k most frequent words. Break ties lexicographically.

Hidden answer: invariant, tests, and Python solution

Invariant: after counting, frequency is the source of truth and sorting only decides rank. Test ties, k = 0, one word, and more requested items than unique words.

from collections import Counter


def top_k_frequent_words(words, k):
    counts = Counter(words)
    ranked = sorted(counts, key=lambda word: (-counts[word], word))
    return ranked[:k]

Drill 2: Merge Intervals With Metadata

Given time intervals [start, end], merge overlaps. Then explain how you would keep aggregate metadata such as total requests or max error rate for each merged interval.

Hidden answer: invariant, tests, and Python solution

Invariant: the output list is sorted and non-overlapping. The last output interval is the only interval that can overlap the current sorted input. Test touching intervals, nested intervals, unsorted input, empty input, and negative timestamps.

def merge_intervals(intervals):
    if not intervals:
        return []

    intervals = sorted(intervals)
    merged = [intervals[0][:]]
    for start, end in intervals[1:]:
        last = merged[-1]
        if start <= last[1]:
            last[1] = max(last[1], end)
        else:
            merged.append([start, end])
    return merged

For metadata, carry an accumulator beside each merged range. Sum counts, take max for peak error rate, and preserve the contributing release IDs for debugging.

Drill 3: Course Schedule

Given num_courses and prerequisite pairs, return whether all courses can be completed.

Hidden answer: invariant, edge cases, and Python solution

Invariant: every node popped from the queue has no remaining prerequisites. If the processed count is less than the course count, the remaining graph contains a cycle. Test no prerequisites, duplicate-looking chains, isolated courses, and a two-node cycle.

from collections import defaultdict, deque


def can_finish(num_courses, prerequisites):
    graph = defaultdict(list)
    indegree = [0] * num_courses

    for course, prereq in prerequisites:
        graph[prereq].append(course)
        indegree[course] += 1

    queue = deque(i for i, degree in enumerate(indegree) if degree == 0)
    seen = 0
    while queue:
        node = queue.popleft()
        seen += 1
        for nxt in graph[node]:
            indegree[nxt] -= 1
            if indegree[nxt] == 0:
                queue.append(nxt)

    return seen == num_courses

Drill 4: Minimum Window Substring

Return the smallest substring of s containing every character in t, including duplicate counts.

Hidden answer: invariant, common mistake, and Python solution

Invariant: when formed == required, the current window satisfies all required counts. Shrink from the left until removing one character would break that invariant. The common mistake is checking only unique membership and ignoring duplicate counts.

from collections import Counter, defaultdict


def min_window(s, t):
    if not t or not s:
        return ""

    need = Counter(t)
    required = len(need)
    have = defaultdict(int)
    formed = 0
    left = 0
    best = (float("inf"), 0, 0)

    for right, ch in enumerate(s):
        have[ch] += 1
        if ch in need and have[ch] == need[ch]:
            formed += 1

        while formed == required:
            if right - left + 1 < best[0]:
                best = (right - left + 1, left, right)

            drop = s[left]
            have[drop] -= 1
            if drop in need and have[drop] < need[drop]:
                formed -= 1
            left += 1

    if best[0] == float("inf"):
        return ""
    return s[best[1]:best[2] + 1]

Production Follow-Ups

Connect Algorithms To Speech ML/AI Work

Follow-Up 1: Streaming ASR Partial Stability

You receive a stream of partial transcripts. Design a function that emits only the longest stable prefix shared by the last three partials.

Hidden answer: strategy and production caveats

Keep a fixed-size deque of recent partials, compute the common prefix across them, and only emit newly committed text. In production, split on tokens rather than raw characters, track churn rate, and reset state at endpointing boundaries.

Follow-Up 2: Inference Queue Backpressure

A model server has request timestamps, deadlines, and estimated token costs. Which coding patterns help decide what to admit, batch, defer, or reject?

Hidden answer: strong system-design mapping

Use heaps for earliest deadline or shortest job first, sliding windows for recent arrival rate, queues for fairness per tenant, and binary search over batch size when latency is a monotonic function of batch size. The strong answer also includes metrics: queue age, drop reason, batch fill ratio, deadline miss rate, and cost per successful request.

Follow-Up 3: RAG Evaluation Failure Buckets

Given evaluation rows with query type, ASR noise level, retrieved document age, answer score, and latency, how would you identify the worst slices?

Hidden answer: data-structure plan

Group by slice keys with a hash map, aggregate count, mean score, p95 latency, and failure rate, then sort by business-weighted regression. Require minimum sample counts so small noisy slices do not dominate the release decision.

Rubric

Self-Grade Each Practice Session

Question: How should this workbook be used with the Blind 75 bank?

Use the Blind 75 bank for breadth, then use this workbook for depth. Pick one pattern, solve two bank problems, write the invariant from memory, and finish by answering one production follow-up in the language of audio ML systems.