Reverse Linked List II (LC 92): a singly linked list, two 1-indexed
inclusive positions left ≤ right, reverse the nodes between them in place.
Every bug in the problem is a pointer left dangling, so the piece draws the
pointers and nothing else: the boxes never move — that is where the nodes
are in memory — and each next is an arrow. A forward pointer to the
neighbour is a straight line; a pointer that skips ahead arcs under the row;
a pointer that goes backward arcs over the top, which is how you see the
reversed run accumulate. The pointer that changed on this frame is white.
Named variables (pre, cur, move) sit under the box they hold, and a
dummy node stands in front of the head so that left = 1 has a pivot like
every other case.
Under the row, walk from head is the list as a traversal would see it
at this exact instant — the nodes reachable from the head, in order, ending
in ∅ — with a verdict: well-formed, or broken with a count of nodes
nobody can reach. That line is the argument for one method over the other.
Head insertion (one pass) walks pre to the node before left, holds
cur on the node at left, and right − left times unlinks cur.next and
splices it in right behind the pivot: three writes, after which the walk
reads well-formed again. The invariant after k iterations — the first
k + 1 nodes of the range sit reversed immediately after the pivot — is
printed on every splice frame, which is what you say when an interviewer
asks how you know it is correct.
Reverse, then stitch walks the same pivot, then runs the classic
three-pointer flip over right − left + 1 nodes and reconnects both ends.
From the first flip to the last stitch the walk from the head is short —
the run hangs off prev alone — so the list is broken for most of the
algorithm. Correct, and harder to narrate under pressure.
Loop count: off by one is the single most common failure here, and it
fails differently per method. Under head insertion the loop runs
right − left + 1 times and drags the node after right into the run —
[1, 5, 4, 3, 2] instead of [1, 4, 3, 2, 5], with no crash and a
well-formed walk, which is why it survives some test cases; set right to
the last node and it dereferences nil instead. Under reverse-then-stitch it
runs one time too few, never flips the node at right, and both stitches
still succeed — a wrong list that looks whole.
Type your own list (up to ten values), pick left and right, step
through one write at a time, or let it run.
Reuse
src/relink.js is a framework-free ES module:
parseList(text, { max, lo, hi })— integers out of free text, capped.reverseBetween(values, left, right)— the plain answer over real nodes, as you would write it in an interview.simulate(values, left, right, { method, offByOne })— runs one method and returnsnodes(id 0 the dummy),frames(one per event, each with a full snapshot of everynextpointer and of the named variables), theexpectedand actualresult, andok/crashed.methodis'insert'or'stitch'. Same trace-per-tick shape asprune,ledger,pincerandwindow.walk(next)— follow the pointers from the dummy:order,cycle,unreachable,intact.
No rendering or timers in the module; the canvas demo is reference code.
Gotchas
- Positions in the controls are the original positions — the boxes never
move, so
leftandrightkeep pointing at the same slots throughout. - The off-by-one under reverse-then-stitch with
left = rightreverses zero nodes, points the pivot at∅and wires the tail to itself; the walk line reports everything past the pivot as unreachable. - The demo bundles its own copy of
relink.js(self-contained by contract); re-copy after editingsrc/.