Skip to content

The coding round, step by step

  • Interview Playbook · Foundations
  • 20 min read, about 1 h with practice
  • Concept
  • Asked often: high
  • Reviewed 2026-11

New to Big O or sorting? Open a quick recap. Each takes about two minutes.

Quick recapBig O· 2 min

Big O says how the work grows with the input size n. O(n) means one pass: twice the input, twice the work. O(n²) means a pass for every item: twice the input, four times the work. At 100,000 items, that’s the difference between a blink and minutes.

Quick recapSorting· 2 min

Python’s sorted() returns a new sorted list and leaves the original alone; list.sort() sorts in place. Both take O(n log n). A list of lists is sorted by the first item, then the second: [[9, 11], [9, 10]] sorts to [[9, 10], [9, 11]].

You studied for weeks. In the interview you get a question you’ve seen before. You type the solution in 10 minutes, the interviewer asks a few questions, and you leave feeling great. A week later: no offer.

What happened? You solved a slightly different problem than the one asked. The interviewer heard nothing for 10 minutes, so they couldn’t tell how you think. And you never tested your code, so you didn’t see the bug they spotted in a second.

Interviewers don’t only score the answer. They score how you get there: how you communicate, solve problems, write code, test and analyze. A method gives all five a place, even when you’re nervous.

The method, in seven steps:

  1. Clarify. Ask about the input, the output and the edge cases. Restate the problem in your words.
  2. Examples. Work a small example by hand, plus one tricky one.
  3. Brute force. Say the simplest correct idea and its cost. Don’t code it yet.
  4. Optimize. Find the slow part and improve it. Agree on the plan with the interviewer.
  5. Code. Write clean code and talk as you go.
  6. Test. Walk through your code with an example, then try the edge cases.
  7. Analyze. State the time and space, and what you’d change for bigger inputs.

The question for this lesson, as an interviewer would say it:

“Our office has meeting rooms. Given a list of bookings, merge the ones that overlap.”

That’s all you get. It sounds clear. It isn’t.

Hint 1 of 3

What does one booking look like? Are the bookings in any order?

Hint 2 of 3

Bookings from 13 to 15 and from 15 to 16: do they overlap? Who decides?

Hint 3 of 3

What should happen with no bookings? With 100,000?

Here is how a strong candidate spends a 45-minute round on this question, minute by minute. The first 5 minutes are introductions, and the last 7 are follow-ups and the candidate’s own questions.

  • Minutes 5–9, clarify. “Is a booking a start and an end, like 9 and 10? Are they sorted? If one ends at 15 and the next starts at 15, do they merge? Can the list be empty? How many bookings? May I change the list I’m given?”

    The interviewer’s answers: bookings are [start, end] pairs of whole hours, with start before end. They come in any order. Touching bookings merge, because the room is busy without a break. The list can be empty and can hold 100,000 bookings. Return the blocks sorted by start, and don’t change the list you’re given.

  • Minutes 9–12, examples. “So 9–10, 13–15, 9–11 and 15–16 become 9–11 and 13–16, because you said touching ones merge. And an empty list gives an empty list.”

  • Minutes 12–14, brute force. “Simplest idea: for each booking, find every block it overlaps and merge them into one. That’s a scan of all blocks per booking: O(n²). Fine for a room, slow for 100,000 bookings.”

  • Minutes 14–18, optimize. “The slow part is searching all blocks. If the bookings were sorted by start, only the last block could overlap the next booking. Sorting costs O(n log n), then one pass. Shall I code that?”

  • Minutes 18–30, code. Writes the Strong code below, saying what each line is for: “I sort a copy so I don’t change your list… <= because touching bookings merge…”

  • Minutes 30–36, test. Walks through the example line by line, then tries: empty, one booking, no overlaps, all touching, one booking inside another.

  • Minutes 36–38, analyze. “O(n log n) time for the sort, O(n) for the pass. O(n) extra space for the sorted copy and the result.”

Three candidates, same question, same 45 minutes. Each one shows what they did, their code and what the interviewer writes down.

Weak

Codes at once, in silence

The idea: “I’ve seen this one.” Types for 8 minutes without a word, runs it on one sorted example, and says it’s done.

  • ✗ No questions. It treats 13–15 and 15–16 as separate and assumes the list is sorted. Both are wrong here.
  • ✗ Silence. For 8 minutes the interviewer has nothing to score but typing.
  • ✗ No testing. It crashes on an empty list, and on the interviewer’s own example it gives 9–10, 13–15, 15–16: the 9–11 booking disappears.
  • ✗ Can change the caller’s data. merged starts with the first booking itself, not a copy, so merged[-1][1] = … can edit the first booking passed in.
"""The weak candidate's code: typed at once, in silence, from memory
of a similar problem. It works on the example they tried, and little
else."""
def merge(bookings):
merged = [bookings[0]] # crashes on an empty list
for start, end in bookings[1:]: # assumes the bookings come sorted
if start < merged[-1][1]: # treats touching bookings as separate
merged[-1][1] = max(merged[-1][1], end) # can edit the caller's first booking
else:
merged.append([start, end])
return merged
Runs in
O(n), but wrong
Likely verdict
no
Why
Fast and confident, on a problem the interviewer didn't ask: it assumes sorted input and that touching bookings stay apart.

What the interviewer writes: “Didn’t clarify. Couldn’t explain the approach. Didn’t test; missed basic cases.”

Decent

A correct brute force, explained

The idea: Asks two questions, talks through a brute force and codes it. Tests the example. Says “O(n), I think” when asked.

  • ✓ Asked about order and touching bookings, so the answer is right.
  • ✓ Talked while coding. The interviewer could follow.
  • ✗ Stopped at the brute force. With 100,000 bookings, scanning every block for every booking is far too slow.
  • ✗ Tested only the example, and guessed the complexity instead of working it out: it’s O(n²), not O(n).
"""The decent candidate's code: a correct brute force. Each booking
swallows every block it overlaps or touches. Right answers, but each
booking scans all the blocks so far: O(n^2)."""
def merge(bookings):
blocks = []
for start, end in bookings:
hits = [b for b in blocks if b[0] <= end and start <= b[1]]
for b in hits:
blocks.remove(b)
start = min([start] + [b[0] for b in hits])
end = max([end] + [b[1] for b in hits])
blocks.append([start, end])
return sorted(blocks)
Runs in
O(n²)
Likely verdict
borderline
Why
It's correct on every input and the reasoning was out loud. But it never looked for a faster way, and the complexity answer was wrong.

What’s missing: the step from brute force to better: find the slow part (searching every block) and remove it. Then test on purpose, and work out the cost line by line.

Strong

All seven steps, out loud

The idea: Clarifies, works examples, and states the brute force and its cost. Finds the sorted-order idea and agrees on the plan. Codes it while talking, tests on purpose and states the cost.

  1. Clarify. Six short questions, in about four minutes. The answers change the code: sort first, and merge on <=.
  2. Examples. The interviewer’s example, plus one where a booking sits inside another (1–10 and 2–3).
  3. Brute force. Said out loud with its cost, O(n²). A safe fallback if time runs out.
  4. Optimize. “After sorting, only the last block can overlap.” Asked “Shall I code that?” before starting.
  5. Code. Sorted a copy, so the caller’s list is untouched. Short names, one idea per line.
  6. Test. Walked through the example, then 5 edge cases from a list made in step 1. Found and fixed one bug: max() for a booking inside another.
  7. Analyze. O(n log n) time for the sort plus O(n) for the pass; O(n) extra space.
"""The strong candidate's code: sort by start, then one pass.
A booking that starts before the last block ends, or exactly when
it ends, joins that block. O(n log n) for the sort, O(n) for the
pass. The caller's list is not changed."""
def merge(bookings: list[list[int]]) -> list[list[int]]:
blocks: list[list[int]] = []
for start, end in sorted(bookings):
if blocks and start <= blocks[-1][1]: # overlaps or touches it
blocks[-1][1] = max(blocks[-1][1], end)
else:
blocks.append([start, end])
return blocks
Runs in
O(n log n)
Likely verdict
yes
Why
Every step gives the interviewer something to score, and the optimization came from naming the slow part of the brute force, not from memory.

It’s not about speed. The strong candidate wrote the first line of code at minute 18, about ten minutes after the weak one. They still ended with working, tested code, because they never had to start over.

Now you code the strong solution. Merge bookings that overlap or touch, return the blocks sorted by start, and don’t change the input list. Hidden tests check that your input is left as it was. A speed test has 40,000 bookings, so the O(n²) brute force fails it.

Merge overlapping bookings

Ctrl + Enter runs

Loads about 6 MB the first time. Best on Wi-Fi.

  1. Not run yet: merge([[9, 10], [13, 15], [9, 11], [15, 16]]) → [[9, 11], [13, 16]]
  2. Not run yet: One booking inside another → [[1, 5]]
  3. Not run yet: Extra test
  4. Not run yet: Extra test
  5. Not run yet: Extra test
  6. Not run yet: Extra test
  7. Not run yet: Extra test
  8. Not run yet: Extra test

Extra tests check tricky cases. You see their input only if they fail.

Try your own input
What interviewers scoreWeakDecentStrong
CommunicationSilent while codingExplains as they goExplains, checks in, agrees the plan first
Problem solvingJumps to a remembered answerCorrect brute force, stops thereBrute force, then names the slow part and fixes it
CodeShort, but wrong and changes inputCorrect, a bit clumsyCorrect, clear, leaves the input alone
TestingNoneThe given example onlyA walk-through, then chosen edge cases
AnalysisNoneA guess, and wrongTime and space, worked out from the code
  • Too many questions is a smell too. Ask the ones that change the code: order, ties and boundaries, empty input, size, and whether you may change the input. Then go.
  • Silence is the most common mistake. If you need to think, say so: “Let me think about how to avoid scanning every block for 30 seconds.” Then share what you found.
  • Stuck? Say what you know and what fails. Try a smaller example by hand, or ask a specific question: “Would it help if the bookings were sorted?” A good hint taken well is not a fail.
  • Test the code you wrote, not the code you meant. Read it line by line with real numbers. Most bugs hide in the boundaries: < or <=, the first item, the last item.
  • Use the language you know best. Python is fine nearly everywhere, and its sorted(), dict and collections are allowed unless the interviewer says otherwise.
  • Running out of time? Say what’s left, finish the core idea, and leave a clear stub for helpers. A working main path beats a half-typed perfect one.

Questions to ask first (on almost any question)

  • What does the input look like, and is it sorted?
  • Can it be empty? Can there be duplicates or ties?
  • How big can it get?
  • What should I return, and in what order? What if there’s no answer?
  • May I change the input?

A 60-second opening, after the question

“Let me check I’ve got it. I get a list of bookings, each a start and an end, in any order. I return the busy blocks sorted by start, with touching bookings merged, without changing the list. For example, 9–10, 13–15, 9–11 and 15–16 become 9–11 and 13–16. The simplest way is to merge each booking into every block it overlaps, which is O(n²). The slow part is searching all the blocks. If I sort by start first, only the last block can overlap the next booking. So it’s one pass after an O(n log n) sort. Shall I code that?”

Likely follow-ups

  • What if bookings arrive one at a time, all day? Keep the blocks in a sorted structure and insert each new booking with a binary search, merging with its neighbours.
  • What if there are too many to fit in memory? Sort them on disk in chunks, then merge the sorted chunks in one pass: the same idea, at a bigger scale.
  • How many rooms do we need? A different question: count how many bookings overlap at the busiest moment. Sort starts and ends, or use a heap.
  • Can you do it in O(1) extra space? Sort the list in place and write the result into it, but only if the caller agrees that you may change their list.

Red flags interviewers notice

  • Coding before asking a single question.
  • Long silences, or talking without saying anything useful.
  • Saying “It works” without trying it.
  • Guessing the complexity, or not knowing what sorted() costs.
  • Arguing with a hint instead of trying it.

Four drills, from easy to hard. Each has a hint or two, then weak, decent and strong answers. Do each one out loud, with a timer, before you open the answers.

The interviewer says: “Return the k most frequent words in a text.” You have two minutes. What do you ask?

Hint 1 of 2

What counts as a word? Is “The” the same as “the”?

Hint 2 of 2

Two words appear the same number of times. Which comes first?

Show the answers
Weak

No questions

The idea: Starts coding a Counter at once.

Questions
none
Risk
solves a different problem
Why
Case, punctuation and ties all change the output. The code may be right for a question nobody asked.
Decent

Asks about the input only

The idea: “How big is the text? Is it all lowercase?”

Questions
two
Risk
ties and k left open
Why
Good start, but the output is still unclear: what happens on a tie, or when k is bigger than the number of words?
Strong

The questions that change the code

The idea: “Is ‘The’ the same as ‘the’? Does punctuation count? On a tie, alphabetical? What if k is bigger than the number of different words? How big is the text: does it fit in memory?”

Questions
five, in under two minutes
Risk
small
Why
Each answer changes a line: lowercasing, the split, the sort key, a bound on k, and Counter versus a streaming count.

“Given a list of numbers, does any value appear twice?” Say the brute force and its cost, then improve it, out loud.

Hint 1 of 2

Compare every pair. How many pairs are there?

Hint 2 of 2

What do you need to remember about the numbers you’ve already seen?

Show the answers
Weak

Jumps to a one-liner

The idea: “return len(set(nums)) != len(nums)”, with no reasoning.

return len(set(nums)) != len(nums)
Runs in
O(n)
What's heard
a memorized trick
Why
Correct, but the interviewer learns nothing about how you'd solve a problem you haven't seen.
Decent

Brute force, then sorting

The idea: “Compare every pair: O(n²). Better: sort, then duplicates sit next to each other, so O(n log n).”

nums = sorted(nums)
return any(a == b for a, b in zip(nums, nums[1:]))
Runs in
O(n log n)was O(n²)
What's heard
clear steps
Why
A real improvement, explained. One step short of the best.
Strong

Name what to remember

The idea: “The brute force rechecks old numbers. If I remember what I've seen in a set, each check is O(1), so one pass is O(n), with O(n) space. If memory is tight, sorting in place is the trade-off.”

seen = set()
for x in nums:
if x in seen:
return True
seen.add(x)
return False
Runs in
O(n)was O(n log n)
What's heard
the slow part, named and removed
Why
It stops at the first duplicate, and the trade-off between time and memory is said out loud.

A candidate wrote this to find the longest run of the same character, like 3 for "aabbbc". It returns 3 for that example. Test it out loud and find the bug.

def longest_run(s):
best = run = 1
for i in range(1, len(s)):
if s[i] == s[i - 1]:
run += 1
else:
best = max(best, run)
run = 1
return best
Hint 1 of 2

Where can the longest run be? Try one at the very end.

Hint 2 of 2

What about an empty string?

Show the answers
Weak

“It works on the example”

The idea: Runs “aabbbc”, gets 3, and stops.

Bugs found
none
Cases tried
one
Why
The example's longest run isn't at the end of the string, so the bug never shows.
Decent

Tries random extra inputs

The idea: Tries “abc” and “abbb”, finds “abbb” gives 1 instead of 3, and patches it.

Bugs found
one, by luck
Cases tried
three
Why
Found the bug, but not on purpose. The empty string still returns 1.
Strong

Edge cases on purpose

The idea: Lists the cases first: empty, one character, all the same, the longest run at the start, in the middle and at the end. “abbb” shows a run at the end is never counted; “” returns 1, not 0.

def longest_run(s):
if not s:
return 0
best = run = 1
for i in range(1, len(s)):
run = run + 1 if s[i] == s[i - 1] else 1
best = max(best, run)
return best
Bugs found
both
Cases tried
six, chosen
Why
Updating best on every step means the last run is counted, and an empty string returns 0.

You’re halfway through the optimal solution with 10 minutes left. The helper that does the tricky part isn’t written yet. What do you do?

Hint 1 of 2

What does the interviewer need to see in the last 10 minutes?

Hint 2 of 2

Could a working simpler version, plus a clear plan, score better than half of the best one?

Show the answers
Weak

Types faster, says nothing

The idea: Rushes the helper in silence and runs out of time mid-line.

At the end
nothing runs
Interviewer knows
little
Why
No working code, no test, and no idea what you planned.
Decent

Finishes, untested

The idea: Writes the helper quickly and says “I think that works.”

At the end
code that may run
Interviewer knows
some
Why
Better, but a bug in the rushed helper is likely and nobody has checked.
Strong

Say the plan, finish the core, test it

The idea: “I have 10 minutes. I'll write the main function with the helper as a stub. I'll explain what the helper does and its cost, then test the main path.” Fills in the helper if time remains.

At the end
a tested main path
Interviewer knows
the whole plan
Why
The interviewer sees working, tested code, knows exactly what's missing, and sees calm time management, which is part of the score.

A few quick questions. Ones you miss are remembered, so you can find your weak spots later.

  1. Pick the patternThe interviewer says: "Merge the bookings that overlap." What do you do first?
  2. Multiple choiceYou can't see a fast solution yet. What's the best next step?
  3. Spot the bugThe candidate's merge passes their one example. Which input breaks it?
    def merge(bookings):
        merged = [bookings[0]]
        for start, end in bookings[1:]:
            if start < merged[-1][1]:
                merged[-1][1] = max(merged[-1][1], end)
            else:
                merged.append([start, end])
        return merged
  4. Predict the outputThe strong solution sorts, then makes one pass. What is its time complexity?
    blocks = []
    for start, end in sorted(bookings):
        if blocks and start <= blocks[-1][1]:
            blocks[-1][1] = max(blocks[-1][1], end)
        else:
            blocks.append([start, end])
  5. Multiple choiceYour code is done with 6 minutes left. What now?

Add these to your review deck. Each card comes back a little later every time you get it right.

  • The steps: clarify, examples, brute force, optimize, code, test, analyze. Out loud.
  • A 45-minute round: about 4 minutes to clarify, 3 for examples, 6 for brute force and optimizing, 12 to 15 to code, 6 to test, 2 to analyze.
  • Ask what changes the code: order, ties and boundaries, empty, size, return value, may I change the input.
  • Brute force first, with its cost. Then name the slow part and remove it.
  • Agree on the plan before you code: “Shall I code that?”
  • Test on purpose: a walk-through, then empty, one, all the same, none, all, the boundary, big.
  • Stuck: say what you know, try a smaller example, ask a specific question.
  • Two Sum: the same method on the most common first question, with a brute force, a hash map and two pointers.
  • Count errors in a 10 GB log: what “it doesn’t fit in memory” changes, a follow-up you’ll hear often.
  • The lesson’s code: content-code/playbook/coding-round/ in this site’s repository, with all three candidates and the tests that show exactly where the weak one fails.

Can you do these now?

If you’re not sure of any of these, scroll back to that part before moving on.

Status: Not started