Working a problem you haven't seen

Lesson 2 of 1010 min read
In this lesson7 sections

An unofficial lesson on the topic of the Technical Questions chapter of Cracking the Coding Interview, 6th Edition by Gayle Laakmann McDowell (2015). PracHub is not affiliated with the authors or publisher. Buy the book

Ten minutes into a coding round, a prompt you have never seen is on the screen and the interviewer has gone quiet to take notes. What they write depends less on whether you knew the problem than on how you work it in front of them. This lesson follows one unfamiliar problem from first read to last check and stops wherever candidates usually lose points, so you know what to say and do at each one.

Here is the problem we'll carry through.

Warehouse orders. You get a list of events in time order. ("restock", item, qty) adds stock of an item. ("order", order_id, item, qty) asks for stock. An order ships whole if stock covers it; otherwise it waits, and waiting orders ship when stock arrives. Return the ids of the orders that shipped, in the order they shipped.

The prompt's example:

EventWhat happens
restock bolts 55 bolts on hand
order A bolts 3A ships, 2 left
order B bolts 4B waits
restock bolts 2B ships, 0 left

Output: ["A", "B"].

What the interviewer is scoring

Interviewers at large companies usually write feedback under a few fixed headings, and correctness is spread across all of them:

AreaWhat earns creditWhat the interviewer sees when it goes wrong
ReasoningRules settled before code; a correct plan with its cost, then a better one with a reasonCode built on a guessed rule, rewritten twice
CommunicationA sentence of intent before each piece; questions that come with a defaultLong silences, or code read aloud token by token
CodeSmall named pieces, clear names, few bugsOne long loop with i, j, tmp and a flag nobody can explain
TestingA hand trace and edge inputs, unprompted"I think that works"

A right answer reached in silence leaves most of that table blank.

A tidy example hides the rule that matters

Say the problem back in a sentence or two. It takes fifteen seconds and catches a misreading while it is still free to fix. Then pin down the inputs (can a quantity be zero?), the sizes, and every rule the prompt leaves open.

Sizes set your budget. With a few hundred events, almost any correct approach is fine. With 100,000 events and thousands of orders waiting, re-checking every waiting order on every event runs to hundreds of millions of steps, too slow in Python.

The open rules are where this problem lives. The prompt's example never has two orders waiting, so it cannot tell you what happens when a restock covers the second waiting order but not the first. Can the smaller one skip ahead? Both are reasonable business rules, with different outputs. Ask, and attach your default so the interviewer can answer in a word:

"Let me say it back: events come in time order, restocks add stock, an order ships whole or waits, and waiting orders ship when stock arrives. Two questions. If the oldest waiting order for an item can't be covered, can a smaller one behind it ship? I'll assume no: first come, first served, per item. And roughly how many events, hundreds or hundreds of thousands?"

Say the interviewer confirms positive quantities, first come, first served, and up to 100,000 events. Saying the rule's consequences shows you understood it. A new order for an item that already has a line joins the back, even if the stock on hand would cover it. And one huge order that is never covered blocks its item forever, which the interviewer may decide they don't want.

Now build your own example. The prompt's is the easy path: one item, one waiting order, each restock just enough. Code that lets a small order skip the line, or ships only one order per restock, or keeps one line for all items, passes it. A useful example has two items, a line of more than one order, a restock that covers only the front of the line, and an order that arrives while stock is on hand but someone is already waiting:

#EventWhat happens
1order A nuts 2waits (0 nuts)
2order B nuts 5waits behind A
3restock nuts 3A ships, 1 nut left; B still needs 5
4order C nuts 1waits: 1 nut on hand, but B is first
5restock bolts 44 bolts
6order D bolts 4ships at once, 0 bolts
7restock nuts 56 nuts: B ships, then C takes the last one

Expected output: ["A", "D", "B", "C"]. Seven events, two minutes by hand, and every rule you asked about gets used. You'll check your code against it later.

What the interviewer sees when a candidate skips this: code that passes the prompt's example, then a long pause when the interviewer asks about event 4.

Going quiet while hunting for the fast version

A candidate sees that the obvious approach is slow and goes quiet, looking for the clever one. Five minutes later the interviewer has nothing to write in any row of the table.

Say a plain correct approach first, with its cost, even if you mean to beat it. Here: after every event, sweep the whole waiting line in order and ship whatever the rules allow.

def ship_orders_plain(events):
    stock, waiting, shipped = {}, [], []
    for event in events:
        if event[0] == "restock":
            _, item, qty = event
            stock[item] = stock.get(item, 0) + qty
        else:
            waiting.append(event[1:])           # (order_id, item, qty)
        still_waiting, blocked = [], set()
        for order_id, item, qty in waiting:     # sweep the whole line
            if item not in blocked and stock.get(item, 0) >= qty:
                stock[item] -= qty
                shipped.append(order_id)
            else:
                blocked.add(item)               # nothing behind it may ship
                still_waiting.append((order_id, item, qty))
        waiting = still_waiting
    return shipped

Let e be the number of events and w the longest the waiting line gets. Each event sweeps the line once, so this is O(e · w) time, which is O(e²) when the line grows with the input, and O(e) space. Name the variables when you say it:

"The simple version sweeps the whole waiting line after every event. That's O(e times w), with e events and w the longest line, so up to O(e squared). At 100,000 events that's too slow. Let me look for something faster; if I don't have it in a couple of minutes, I'll code this one and improve it after."

That last sentence tells the interviewer you have a working fallback and a time limit. Making a slow solution fast covers how to find the faster version, and Big O as you'd say it in an interview covers stating a cost precisely.

Stuck, or handed a hint

Being stuck is normal; silence while stuck is what costs you. Put the problem into words precise enough to answer: "Every sweep re-checks orders for items that didn't change, and I don't see how to skip them" gives the interviewer something to respond to. "Hmm, let me think" does not.

When a hint comes, use it quickly. Here a typical hint is: "Does a bolts restock ever change what happens to a nuts order?" Weak replies agree and carry on with the old plan, or defend the sweep. A strong reply repeats the point, draws the consequence and acts on it:

"No, items never affect each other. So each item can keep its own line, oldest first, and an event only has to look at the front of its own item's line."

If a hint doesn't make sense to you, ask one short question about it rather than nodding. A hint used within a minute usually costs far less than ten silent minutes. If the faster idea still won't come, code the plain version: working code with a known cost scores better than half of a clever one.

Code that only you can follow

Talk in intent, not syntax. The interviewer can read for event in events themselves; saying it aloud tells them nothing. Say what the next piece is for and what will be true when it's done:

"Once a new order joins the back of its item's line, placing an order and restocking end the same way: ship from the front of that line while stock covers the front order. So I'll write that once, as a helper."

Then put each rule in a small function whose name says what it does. The main loop reads like the prompt, and if time runs out, a helper whose name and purpose are written down can still be graded.

from collections import defaultdict, deque

def ship_orders(events):
    stock = defaultdict(int)
    lines = defaultdict(deque)   # item -> waiting (order_id, qty), oldest first
    shipped = []

    def ship_waiting(item):
        line = lines[item]
        while line and line[0][1] <= stock[item]:
            order_id, qty = line.popleft()
            stock[item] -= qty
            shipped.append(order_id)

    for event in events:
        if event[0] == "restock":
            _, item, qty = event
            stock[item] += qty
        else:
            _, order_id, item, qty = event
            lines[item].append((order_id, qty))
        ship_waiting(item)
    return shipped

Each order is appended once and popped at most once, and each call to ship_waiting makes at most one failed comparison besides its pops. The whole run is O(e) time, counting dict operations as O(1) on average, and O(e) space.

Calling it done without a trace

"I think that works" is the weakest way to end a coding round. Before you say you're done, run your own example through the code by hand, tracking each variable as the code changes it, not as you meant it to:

#Eventnuts on handnuts linebolts on handShipped
1order A nuts 20A0
2order B nuts 50A, B0
3restock nuts 31B0A
4order C nuts 11B, C0A
5restock bolts 41B, C4A
6order D bolts 41B, C0A, D
7restock nuts 500A, D, B, C

The trace earns its time. A first draft of ship_waiting often has if where it needs while, and the prompt's example cannot tell them apart, because no restock there ships two orders. Event 7 does: with if, B ships and C stays waiting. Writing < for <= fails at event 6, where the bolts on hand exactly cover D. When the trace shows a bug, say what you saw, fix that line, and re-check the events it affects.

Then the edges, a few seconds each: no events at all, a restock for an item nobody ordered, and an order larger than any stock that ever arrives, which should never ship and should hold back every later order for that item. Say each input and what the code does with it. The interviewer sees a candidate who tests without being asked.

Practicing on simulation questions

Simulation and bookkeeping prompts suit this practice: the rules are long and the code is short, so most of the points are in the reading and the checking. Pick a question from this page, set a 40-minute timer and talk out loud the whole way, ideally recorded. Before any code, write your restatement, your questions with a default for each, and an example that exercises every rule. After coding, trace that example in a table like the one above before running anything. Compute dasher pay from order events is a good first one: stop once your example is written and check it against the prompt line by line.

All simulation questions