The Practical Coding Round
- Run one spec-driven loop on every prompt: read it all, model the input, match the output
- Work three practical builds: quiet time per zone, an inventory processor, and a ledger
- Treat correctness as the floor and readable, defensible code as the bar
Scale AI's coding screen is a build. It runs on HackerRank for around fifty minutes and hands you a realistic task with a written spec. You parse some structured input, compute something specific over it, and print output in an exact shape. Nobody hides a named-algorithm trick in it, though collections, dictionaries, and interval logic still sit underneath the realistic framing. The screen checks how closely you read. Build exactly what the spec asks, named edges included, and print it in exactly the shape it wants.
Read the spec before you type
Run the same loop on every practical prompt, in order. Read the whole spec first. The second part usually consumes the first part's result, and the ending decides how you model the start. Then name the input model out loud. It might be records grouped by a key, intervals you sort and sweep, or commands applied to a small piece of state. Only then write plain code for that model, and walk the edge cases the spec names by hand. Skip ahead to code from the surface story and you'll build the wrong data model, then discover at minute forty that the output shape never fit.
The output contract is part of the problem. Each problem below pins an exact result shape, such as a sorted list of pairs, a specific return per command, or a status line with fixed spacing and wording. Read that shape first and it tells you what to compute and how to store it as you go, so you build toward the contract instead of bending a finished answer to fit. Match ordering and whitespace exactly. A correct computation in the wrong shape fails the same automated check as a wrong answer.
Green tests don't end the grading. A candidate can solve every part, watch each case pass, and still be turned down, because Scale grades the engineering under the checkmark. The interviewer is asking whether a teammate could own the code, whether the data model fits the domain, and whether your choices hold up when they ask why. Progress is weighted heavily, so get a working solution early and make it legible after. Each problem below is an ordinary structure dressed as a realistic build, with the output contract treated as law.
Event records and quiet time per zone
The most representative Scale shape hands you structured records with timestamps and identifiers and asks for one specific quantity. Here the records are activity events, each tagged with a zone and an active window, and you want to know how long each zone sits with nothing active. Strip the framing and you're grouping by a key, merging overlapping intervals inside each group, and summing the gaps. It's a first-year interval sweep inside a reporting task. Precision is won or lost on the output contract, a sorted list of zone and quiet-time pairs.
Event Records: Quiet Time Per Zone
Problem
events where events[i] = [zone, start, end]. zone is a string, and start and end are integers with start < end, describing a half-open window [start, end) during which something is active in that zone.For each zone, consider its observation span, from the earliest
start to the latest end among that zone's events. Return the total time inside that span when none of the zone's events are active. That's the sum of the gaps between the zone's merged active windows.Return a list of
[zone, quiet_time] pairs sorted by zone in ascending order. Windows that merely touch, like [0,2] and [2,5], count as continuous and leave no gap between them. A zone with a single event has no gaps, so its quiet time is 0. If events is empty, return an empty list.Input: events = [["downtown",0,4],["downtown",6,10],["harbor",0,5],["harbor",2,3]]
Output: [["downtown",2],["harbor",0]]
Downtown is active over [0,4] and [6,10] inside the span [0,10], leaving one gap of length 2 from time 4 to 6. Harbor merges to [0,5] with no gap, so its quiet time is 0.
Input: events = [["z",0,2],["z",2,5],["z",7,8]]
Output: [["z",2]]
[0,2] and [2,5] touch and merge to [0,5]. The span runs to 8, so the gap from 5 to 7 is 2.
Group the events by zone into a dictionary. Inside each zone, sort by start, sweep once to merge touching or overlapping windows, and add up the active length. Quiet time is the full span, last end minus first start, minus the total active length. Read the zones out in sorted order.
Event Records: Quiet Time Per Zone
Click "Run" to execute your code
Test Cases
[[["downtown",0,4],["downtown",6,10],["harbor",0,5],["harbor",2,3]]]Expected: [["downtown",2],["harbor",0]][[]]Expected: [][[["a",5,9]]]Expected: [["a",0]][[["z",0,2],["z",2,5],["z",7,8]]]Expected: [["z",2]][[["b",0,1],["a",0,1],["c",0,3],["c",5,6]]]Expected: [["a",0],["b",0],["c",2]][[["x",0,10],["x",1,2],["x",3,4]]]Expected: [["x",0]]A stateful command processor to spec
A second recurring shape asks for several small pieces of functionality over shared state, each with a defined return. Here the state is an in-memory inventory with four commands. You add stock, remove stock without going negative, report the grand total, and name the item with the most stock. The round runs a sequence of commands and checks every return in order. Underneath, it's a dictionary of counts. What's tested is whether each command does exactly what the spec says, and the two edge rules it calls out matter most.
Inventory: A Stateful Command Processor
Problem
Inventory class that tracks integer stock counts per item, starting empty. It supports four operations, each with an exact return value:-
add(item, qty): increase item's count by qty (a positive integer) and return the item's new count.-
remove(item, qty): decrease item's count by qty, but never below 0, and return the item's new count. Removing from an item not yet seen leaves it at 0.-
total(): return the sum of all item counts.-
top(): return the item with the highest count. Break ties by returning the lexicographically smallest item name. Ignore items whose count is 0, and return the empty string "" when no item has a positive count.Input: ops = [add("apple",3), add("banana",5), add("apple",2), remove("banana",10), total(), top()]
Output: [3, 5, 5, 0, 5, "apple"]
Apple reaches 5, banana is floored at 0 by the oversized remove, the total is 5, and apple is the only item with a positive count.
Input: ops = [add("c",1), add("a",1), add("b",1), top()]
Output: [1, 1, 1, "a"]
All three tie at 1, so top returns the lexicographically smallest name, "a".
Keep a dictionary from item to its count. The add and remove commands read, adjust, and write back the count, with remove clamped at 0. The total command sums the values. For top, scan items in sorted name order and keep the first that strictly beats the running best count. That yields the smallest name among the highest counts.
Inventory: A Stateful Command Processor
Click "Run" to execute your code
Test Cases
[["Inventory",[]],["add",["apple",3]],["add",["banana",5]],["add",["apple",2]],["remove",["banana",10]],["total",[]],["top",[]]]Expected: [null,3,5,5,0,5,"apple"][["Inventory",[]],["top",[]],["total",[]]]Expected: [null,"",0][["Inventory",[]],["add",["c",1]],["add",["a",1]],["add",["b",1]],["top",[]]]Expected: [null,1,1,1,"a"][["Inventory",[]],["add",["x",2]],["remove",["x",5]],["add",["x",1]],["top",[]]]Expected: [null,2,0,1,"x"][["Inventory",[]],["remove",["ghost",3]],["total",[]]]Expected: [null,0,0]undo() that reverts the most recent add or remove. Push each mutating operation's before-state onto a stack as you apply it, so undo pops and restores in O(1) with no history replay. It's a common mid-round escalation. It rewards keeping add and remove small and symmetric, with the count write-back in one place you can wrap.Parse and format to an exact contract
Candidates underestimate the third shape, a straightforward transform whose whole difficulty is the output format. You process a sequence of ledger entries and keep a running balance per account. A stated rule rejects some entries. Each entry produces one status line with exact wording and spacing. The computation is a dictionary of running totals and a comparison. The grade is whether every line matches the contract to the character, because the checker compares strings.
Ledger: Running Balance with an Exact Output
Problem
entries where entries[i] = [account, action, amount]. account is a string, action is either "credit" or "debit", and amount is a positive integer. Each account's balance starts at 0, and entries are processed in order.A
credit always applies, adding amount to the account's balance. A debit applies only if it would not take the balance below 0; a debit that would overdraw is rejected and leaves the balance unchanged. A debit that lands the balance exactly at 0 is allowed.Return a list of status strings, one per entry in order, in this exact format. For an applied entry:
" -> " . For a rejected debit: " -> REJECTED" . The tokens are separated by single spaces, and the arrow is a space, hyphen, greater-than, space.Input: entries = [["ana","credit",100],["ana","debit",30],["ana","debit",90],["bob","debit",10]]
Output: ["ana credit 100 -> 100","ana debit 30 -> 70","ana debit 90 -> REJECTED","bob debit 10 -> REJECTED"]
Ana rises to 100, drops to 70, then the 90 debit would overdraw to -20 and is rejected. Bob starts at 0, so any debit is rejected.
Input: entries = [["a","credit",10],["a","debit",10],["a","debit",1]]
Output: ["a credit 10 -> 10","a debit 10 -> 0","a debit 1 -> REJECTED"]
The debit to exactly 0 is allowed; the next debit would go to -1 and is rejected.
Keep a dictionary from account to running balance. For a credit, add and print the new balance. For a debit, check whether balance minus amount is at least 0. If so, apply it and print the new balance. Otherwise print REJECTED and leave the balance untouched. Build each line by joining the fixed tokens exactly.
Ledger: Running Balance with an Exact Output
Click "Run" to execute your code
Test Cases
[[["ana","credit",100],["ana","debit",30],["ana","debit",90],["bob","debit",10]]]Expected: ["ana credit 100 -> 100","ana debit 30 -> 70","ana debit 90 -> REJECTED","bob debit 10 -> REJECTED"][[]]Expected: [][[["x","credit",50]]]Expected: ["x credit 50 -> 50"][[["x","debit",5]]]Expected: ["x debit 5 -> REJECTED"][[["a","credit",10],["b","credit",20],["a","debit",5],["b","debit",25]]]Expected: ["a credit 10 -> 10","b credit 20 -> 20","a debit 5 -> 5","b debit 25 -> REJECTED"][[["a","credit",10],["a","debit",10],["a","debit",1]]]Expected: ["a credit 10 -> 10","a debit 10 -> 0","a debit 1 -> REJECTED"]Spending the fifty minutes
All three problems are built the same way. An ordinary data structure, whether a dictionary of groups, a small piece of state, or a running total, sits inside a realistic task with a rigid output contract. No trick is hidden. The hard part is scope and precision with the clock running, which is why how you spend the fifty minutes matters more than raw speed.
Common questions
Is the Scale AI coding round really not LeetCode?
Right. The screen runs on HackerRank for around fifty minutes and is practical and spec-driven, so you read a realistic task, model the input, and produce an exact output. Drilling named LeetCode archetypes in isolation aims at the wrong test. The fundamentals still matter, from collections and dictionaries to strings, dates, and intervals, but practice building to a spec and hitting a strict output format.
How do I practice for a spec-driven screen?
Force the loop in order on every practice prompt. Read the whole spec, model the input as a concrete structure, build exactly what it asks, then test the named edge cases by hand. Take a plain reporting or command-processing task that groups records by a key, keeps a small piece of state, and prints an exact line. Check your output against the contract character for character. Building toward the output shape is the habit that transfers.
I passed every test case. Why would I still fail?
Scale grades the engineering underneath the visible tests: whether a teammate could own the code, whether the data model fits the domain, and whether your choices hold up when the interviewer asks why. A brittle solution that squeaks past the assertions can score below a clean one a reviewer trusts. Get a working solution early, then make it legible, and be ready to defend every decision.
Key Takeaways
- ✓Scale AI's practical screen is a build to a spec. Read the whole spec first, model the input, build exactly the stated behavior, handle the named edge cases, and match the output contract to the character. Standard computer science sits underneath a realistic skin.
- ✓The quiet-time problem is grouping plus an interval sweep. Bucket events by zone, merge touching windows with an at-or-before test, and subtract the active length from the span. The graded edges are treating touching windows as continuous and sorting the pairs by zone.
- ✓The inventory processor is a dictionary of counts, and two edge rules decide it. Remove must clamp at zero. Top must break ties toward the smallest name and ignore zero counts.
- ✓The ledger problem is a running total whose whole difficulty is the exact output. Allow any debit that keeps the balance at or above zero, including one that lands exactly on zero. Build each status line from the literal tokens, since the checker compares strings and a stray space or number fails a correct computation.
- ✓Passing the visible tests is the floor. Reach a working solution early because progress is weighted heavily. Then make it readable and defensible, because the round grades structure and judgment as well as a green run.
Scale AI interview guideKnow what Scale AI asks before you walk in.
8 coding · 3 system design · 18 behavioral questions
Get their questions first.
InterviewLegend is independent and not affiliated with or endorsed by any company it covers.