Intuition
Advance a fast pointer n nodes ahead of a slow pointer, then move both together. When fast reaches the end, slow sits exactly on the node before the one to remove — so unlink it in a single pass.
Explanation
Idea
To find the nth node from the end in one pass, keep two pointers exactly n nodes apart. When the leading pointer falls off the end, the trailing pointer is n from the end — positioned just before the node to delete.
A dummy node in front of the head elegantly handles the edge case of removing the very first node (no special-casing).
Algorithm
- Create
dummy -> head; setfast = slow = dummy. - Advance
fastbynsteps. - Move
fastandslowtogether untilfast.nextisNone. Nowslowis the node before the target. - Unlink:
slow.next = slow.next.next. - Return
dummy.next.
Worked example: list 1→2→3→4→5, n = 2
- fast advances 2 → points at node
2. - Move both until
fastis the last node (5): fast walks2→3→4→5, slow walksdummy→1→2→3. slow is at node3. slow.nextis4(the 2nd from the end) → skip it:3→5.
Result: 1→2→3→5.
Complexity
- Time: O(sz) — a single pass.
- Space: O(1).
Implementation
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode fast = dummy, slow = dummy;
for (int i = 0; i < n; i++) {
fast = fast.next;
}
while (fast.next != null) {
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummy.next;
}
}