Coding Track

Blind 75 Linked Lists, Binary Search, And Heaps

Practice pointer invariants, monotonic predicates, priority queues, and production-style follow-ups that connect coding rounds to production ML systems.

Interview Method

Name The Invariant Before The Loop

These patterns are less about memorized syntax and more about keeping a precise invariant while the data structure changes. State what each pointer, boundary, or heap entry means before writing code.

  1. Linked lists: say which links have already been rewired and which node still owns the unreversed suffix.
  2. Binary search: define the search interval and whether the answer is inside, left of, or right of the midpoint.
  3. Heaps: define what priority means and how stale entries are rejected.
  4. Tests: empty input, one element, two elements, duplicates, all equal values, and boundary answers.
Question: Why do advanced practiceers care about invariants?

Invariants make correctness auditable. An experienced engineer can explain why the loop terminates, why no data is lost during mutation, and why edge cases are covered without relying on lucky sample tests.

Linked Lists

Pointer Changes Need A Before And After Story

Worked Linked List 1: Reverse Linked List

Given the head of a singly linked list, reverse the list and return the new head.

Hidden answer: invariant, common mistake, and Python solution

Invariant: prev is the fully reversed prefix and cur is the first node in the unreversed suffix. The common mistake is overwriting cur.next before saving the original next node.

def reverse_list(head):
    prev = None
    cur = head
    while cur:
        nxt = cur.next
        cur.next = prev
        prev = cur
        cur = nxt
    return prev

Worked Linked List 2: Merge K Sorted Lists

Given several sorted linked lists, merge them into one sorted linked list.

Hidden answer: invariant, test cases, and Python solution

Invariant: the heap contains the smallest unmerged node from each active list. Use a tie-breaker counter because Python cannot compare list node objects directly. Test empty input, empty lists inside the input, duplicate values, one list, and lists with negative values.

from heapq import heappop, heappush

def merge_k_lists(lists):
    heap = []
    counter = 0
    for node in lists:
        if node:
            heappush(heap, (node.val, counter, node))
            counter += 1

    dummy = ListNode(0)
    tail = dummy
    while heap:
        _, _, node = heappop(heap)
        tail.next = node
        tail = tail.next
        if node.next:
            heappush(heap, (node.next.val, counter, node.next))
            counter += 1

    tail.next = None
    return dummy.next

Blind 75 Prompt: Linked List Cycle

Determine whether a linked list contains a cycle.

Hidden answer: strategy and mistakes

Use Floyd's slow and fast pointers. If the fast pointer reaches null, the list terminates; if slow and fast meet, there is a cycle. Common mistakes are advancing fast.next.next before checking fast and fast.next, or returning false after only one unequal step.

Heaps

Prioritize The Next Useful Item

Worked Heap 1: Find Median From Data Stream

Design a data structure that supports adding numbers and returning the current median.

Hidden answer: invariant, common mistake, and Python solution

Invariant: the max heap stores the smaller half and the min heap stores the larger half; their sizes differ by at most one. Python only has a min heap, so store negative values for the lower half.

from heapq import heappop, heappush

class MedianFinder:
    def __init__(self):
        self.low = []
        self.high = []

    def addNum(self, num):
        heappush(self.low, -num)
        heappush(self.high, -heappop(self.low))
        if len(self.high) > len(self.low):
            heappush(self.low, -heappop(self.high))

    def findMedian(self):
        if len(self.low) > len(self.high):
            return -self.low[0]
        return (-self.low[0] + self.high[0]) / 2

Worked Heap 2: Top K Frequent Elements

Given an array of integers, return the k most frequent values.

Hidden answer: strategy, tests, and Python solution

Count first, then keep a min heap of size k. The heap contains the current top candidates. Test k = 1, k equal to the number of distinct values, ties, and an input with one repeated value.

from collections import Counter
from heapq import heappush, heappushpop

def top_k_frequent(nums, k):
    heap = []
    for value, count in Counter(nums).items():
        item = (count, value)
        if len(heap) < k:
            heappush(heap, item)
        else:
            heappushpop(heap, item)
    return [value for _, value in heap]

Production Follow-Ups

Connect Coding Patterns To ML Systems

Prompt 1: Streaming Top-K ASR Errors

You receive aggregate ASR error events by phrase and need to maintain the top 20 regressions for a live dashboard.

Hidden answer: data structure and caveats

Use counts keyed by phrase plus a heap for top-k candidates. For a high-volume stream, handle stale heap entries by comparing the heap count against the latest count map when popping. Discuss windowing, tenant isolation, privacy redaction, and whether exact counts are required or approximate heavy hitters are enough.

Prompt 2: Rollback Boundary Search

A model rollout ramped from 1 percent to 50 percent. At some point, TTS p99 latency crossed the SLO. How do you find the smallest unsafe ramp level?

Hidden answer: binary-search framing

If the same traffic replay shows latency worsening monotonically as exposure increases, binary search the exposure level with a predicate like p99_latency <= slo. In live systems, monotonicity can be broken by traffic mix and autoscaling, so pair the search with controlled replay, repeated trials, and slice-level checks before making a rollback rule.