A circular route of gas stations, unrolled into a row. Each station is one bar: net = gas − cost, green up when the station gives more than the leg out of it costs, red down when it doesn’t. Gas Station (LC 134) runs across the row one station at a time, and under the bars the tank is drawn as a line — up on a green station, down on a red one, and the moment it goes negative the point turns red and says ran dry.
The thing to watch is what happens next. With the one pass method, the failure doesn’t just end an attempt: every station from the current start to the failure gets crossed through at once, because each of them was reached with fuel to spare and still died here, so starting there with an empty tank cannot do better. The start flag jumps past the failure and the walk carries on from where it was — it never backs up. Underneath, each attempt is a row, and the rows tile the array without overlapping: every station appears in exactly one row, which is the O(n) bound drawn rather than asserted. The walk also never takes a second lap; the result panel carries Σ net the whole time, and that sign — not the walk — is what settles the −1 case.
Switch the method to every start and the same input runs the O(n²) baseline: start 0 walks until it dies, then start 1 walks from an empty tank over the stations start 0 already crossed, and the rows pile up on top of each other. The station-visit counter in the readout is the same number for both methods; the ceiling next to it changes from n to n².
The final check select is the classic bug. The correct finish is
Σ net ≥ 0 ? start : −1; set it to return start and the walk behaves
identically until the last frame, where it returns whatever start survived —
a real index on an infeasible instance, or n itself when the last station
was the one that ran dry. The verdict line says WRONG and names the two
quantities that were conflated: the tank, which reset to 0, and the total,
which never did. Example 1 and Example 2 load the problem’s own
inputs; new arrays rolls a fresh instance with at most one valid start,
matching the problem’s uniqueness promise.
Reuse
src/circuit.js is a framework-free ES module:
makeInstance(n, { span, rand })— randomgasandcostin0..span−1, rejecting instances with two or more valid starts.netOf(gas, cost)— the collapsed array.canCompleteCircuit(gas, cost)— the one-pass answer, as you would write it in an interview.validStarts(gas, cost)— the brute-force truth, every index a lap closes from.simulate(gas, cost, { method, check })— one frame per station visited with the tank, the running total, the start under test, whether this frame ran dry, which stations that ruled out, a snapshot of every attempt so far as{ from, len, state }rows, a running visit count, and a one-sentence note; then a verdict frame with the answer and whether it matches the truth.method: 'brute'walks every start;check: falsereproduces the missing-total-check bug. Same trace-per-tick shape ascleave,coalesceandwindow.
No rendering or timers in the module; the canvas demo is reference code.
Gotchas
- Under
check: falsethe answer is only wrong when Σ net < 0 — on a feasible instance the bug is invisible, which is the lesson. Example 2 is the two-second reproduction. - When more than one valid start exists (only possible with hand-set arrays; the generator rejects them) both methods return the smallest, and the verdict lists all of them.
- The demo bundles its own copy of
circuit.js(self-contained by contract); re-copy after editingsrc/.