Learning/Linked List

Linked List

11 questions. The section where almost every bug is the same bug: you overwrote a pointer before saving what it pointed at.

The one idea

A linked list has no indices, no length, and no way to go backwards. All you ever hold is a handful of pointers into a structure that you are also rewiring. So:

Before you overwrite a pointer, save what it pointed at. Your only reference to the rest of the structure is the pointer you are about to destroy.

Every question here is that discipline plus one technique.

Reversing a list with three pointers
Reversing a list with three pointers

The four techniques

1. Pointer reversal — flip every next, carrying prev, cur and a saved next. (Q1, and reused inside Q3 and Q11)

2. The dummy head — allocate a throwaway node in front of the list so that "append the first node" and "remove the head" stop being special cases. (Q2, Q4, Q6, Q9, Q10, Q11 — six of eleven)

The dummy head removes the empty-list special case
The dummy head removes the empty-list special case

3. Two pointers — in two flavours, and it's worth keeping them distinct:

4. Compose two structures — when one structure can't give you both properties you need, wire two together. (Q9)

Floyd's cycle detection — the one to actually understand

Two pointers, one moving twice as fast. If there's a cycle they must meet, because the gap between them shrinks by exactly 1 each step and a quantity decreasing by exactly 1 cannot skip zero.

Why fast must catch slow
Why fast must catch slow

Finding where the cycle starts needs one more step, and one piece of algebra:

Why resetting to the head finds the entrance
Why resetting to the head finds the entrance

slow walked a + b; fast walked twice that. If fast lapped once, it walked a + b + (b + c). So 2(a+b) = a + 2b + c, giving a = c — the head-to-entrance distance equals the meeting-point-to-entrance distance.

This is what makes question 8 possible, where there is no list at all — just an array whose values happen to be valid indices.

The null-check that appears everywhere

Java
while (fast != null && fast.next != null)

Both clauses, in that order. fast.next.next dereferences twice, so you must establish both before hopping — and && short-circuits, so swapping the operands throws on a null head.

The traps

TrapSymptom
Overwriting cur.next before saving itThe rest of the list is unreachable
prev = cur before cur.next = prevSelf-loop; infinite list
Forgetting slow.next = null when splitting (Q3)Halves stay joined; weave never terminates
while (fast != null) instead of fast.next != null (Q4)slow lands one node too far
Dropping the final carry (Q6)99 + 1 returns 0, not 100
Comparing slow.val == fast.val (Q7)Duplicate values look like a cycle
Singly linked list in an LRU (Q9)Unlink becomes O(n); the design collapses
Merging k lists one at a time (Q10)O(N·k) — the accumulator is re-walked
Reversing before checking k nodes remain (Q11)A partial tail gets reversed and can't be cheaply undone

Verification

Every Java snippet in this section was compiled and cross-checked against an independent implementation — 5,000+ randomized cases, including:

Two deliberately-broken variants confirm the guards are load-bearing rather than decorative: