The Problem

Given the head of a linked list, remove the nth node from the end of the list and return its head.

For example, given the list 1 โ†’ 2 โ†’ 3 โ†’ 4 โ†’ 5 and n = 2, the 2nd node from the end is 4. After removing it, the list becomes 1 โ†’ 2 โ†’ 3 โ†’ 5.

You are asked to do this in one pass.

Interactive Visualization

Speed:
Linked List Visualization
Code
fun removeNthFromEnd(head: ListNode?, n: Int): ListNode? {    val dummy = ListNode(0).also { it.next = head }    var fast: ListNode? = dummy    var slow: ListNode? = dummy    for (i in 0....n) {  // advance fast n+1 ahead        fast = fast?.next }    while (fast != null) {  // move both until fast hits null        fast = fast?.next        slow = slow?.next }    slow?.next = slow?.next?.next  // skip the target    return dummy.next }
Status
Press Step or Play to begin.

How It Works

Key Insight

To find the nth node from the end in a single pass, we use a two-pointer gap technique. If we maintain a gap of exactly n + 1 between a fast pointer and a slow pointer, then when fast reaches the end (null), slow will be pointing to the node just before the target node. This lets us simply unlink the target by setting slow.next = slow.next.next.

The Algorithm

  • Dummy node: Create a dummy node pointing to head. This handles the edge case where the head itself needs to be removed.
  • Phase 1 โ€” Create gap: Advance fast by n + 1 steps from dummy. Now there is a gap of n + 1 nodes between fast and slow.
  • Phase 2 โ€” Move together: Advance both fast and slow one step at a time until fast is null.
  • Phase 3 โ€” Remove: slow is now right before the target node. Set slow.next = slow.next.next to skip over it.
  • Return: Return dummy.next (the new head of the list).

Complexity

Time O(n)
Space O(1)

We traverse the list once with the fast pointer and once (partially) with the slow pointer, giving linear time. Only a constant number of extra pointers are used โ€” no auxiliary data structures needed.