All questions

Linked List Detect Cycle

Premium

Linked List Detect Cycle

You're given the head of a singly linked list. Each node has a value and a next pointer. In a clean list, walking next pointers eventually lands you on null — the list ends. In a cyclic list, walking next eventually lands you back on a node you've already visited, and the walk never terminates. Your job is to return true if the list contains a cycle, false otherwise — using O(1) extra space.

Signature

type Node = { value: unknown; next: Node | null };

// Returns true if walking `next` from head ever revisits a node.
// Returns false if the walk terminates at `null`.
function linkedListDetectCycle(head: Node | null): boolean;

Examples

// Clean linear list: 1 -> 2 -> 3 -> null
const a = { value: 1, next: null };
const b = { value: 2, next: null };
const c = { value: 3, next: null };
a.next = b; b.next = c;
linkedListDetectCycle(a); // false
// Tail loops back to the head: 1 -> 2 -> 3 -> 1 -> ...
const a = { value: 1, next: null };
const b = { value: 2, next: null };
const c = { value: 3, next: null };
a.next = b; b.next = c; c.next = a;
linkedListDetectCycle(a); // true
// Tail loops to the middle: 1 -> 2 -> 3 -> 4 -> 5 -> 3 -> ...
linkedListDetectCycle(headOfThatList); // true
// Empty list and self-loops.
linkedListDetectCycle(null);                       // false
const x = { value: 1, next: null }; x.next = x;
linkedListDetectCycle(x);                          // true

Notes

  • Boolean only. Tests check === true and === false. Don't return the cycle start node, the cycle length, or a truthy/falsy value of another shape.
  • Constant extra space. Don't allocate a Set or Map of visited nodes — that's O(n) and the test for a 1000-node list checks that your solution stays linear in time but doesn't keep growing memory.
  • Don't mutate nodes. A "trick" solution that marks each node with a visited = true flag (or rewrites next) destroys the caller's data. There's an explicit test that the input list is byte-for-byte unchanged after the call.
  • Don't recurse. A recursive walk blows the call stack on a 1000-node list. Tests run with the default Node stack size.
  • null head is valid input. An empty list trivially has no cycle — return false, don't throw.
  • The cycle can start anywhere. It might loop the whole list (tail-to-head), loop a suffix (tail-to-middle), or be a length-1 self-loop (head.next === head). All three are real cycles.

Unlock the solution & editor

  • Runnable editor + tests

    Solve in the browser with instant Jest feedback.

  • Detailed solutions

    Walkthroughs, edge cases, and complexity notes.

  • Multi-framework variants

    React, Vue, Vanilla, Angular — same question, different stacks.

Upgrade to Premium