Fast and slow pointers

Two pointers at different speeds find the middle, detect a cycle, and locate where it starts.

Move one pointer one step at a time and another two. The gap between them grows by one per iteration, and that simple fact answers three separate questions in O(1) space.

Find the middle

function middle(head) {
  let slow = head;
  let fast = head;

  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;
  }

  return slow;   // fast covered 2x, so slow sits at the midpoint
}

For an even-length list this lands on the second of the two middles. If you need the first, start fast at head.next — decide which you want, and say so.

Detect a cycle (Floyd's algorithm)

function hasCycle(head) {
  let slow = head;
  let fast = head;

  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;
    if (slow === fast) return true;
  }

  return false;    // fast reached the end: no cycle
}

Why it must meet: inside a loop of length L, the fast pointer gains one position per step on the slow one, so it closes any gap within L steps. It cannot jump over — the gap changes by exactly one.

O(n) time, O(1) space. The hash-set version is also O(n) time but O(n) space; mentioning both and choosing Floyd's is the expected answer.

Find where the cycle starts

function cycleStart(head) {
  let slow = head, fast = head;

  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;

    if (slow === fast) {                 // they met inside the loop
      let entry = head;
      while (entry !== slow) { entry = entry.next; slow = slow.next; }
      return entry;                      // the node where the loop begins
    }
  }

  return null;
}

The reset step falls out of the algebra: if the distance from the head to the loop entry is a and the meeting point is b into the loop, then a and the remaining distance to the entry are congruent modulo the loop length. Two pointers moving one step each therefore meet exactly at the entry.

Where else it applies

Duplicate detection in an array where values are indices ("find the duplicate number") is the same cycle problem in disguise — treat a[i] as a next pointer and run Floyd's. That reframing is the entire trick to a famously hard question.