Linked List · LC #19
Remove Nth Node From End
Remove the nth node from the end of a linked list in one pass using a two-pointer gap technique. The dummy node handles head-removal edge cases cleanly.
Statement
Problem & Approach
Problem statement, sample I/O, and key reasoning.
Given the head of a linked list, remove the nth node from the end of the list and return its head.
Sample I/O
Input: head = [1,2,3,4,5], n = 2 Output: [1,2,3,5] Input: head = [1], n = 1 Output: []
Intuition
How to Think About It
Intuition
If we advance a fast pointer exactly n+1 steps ahead of a slow pointer, both pointers move together until fast falls off the end of the list. At that point slow is exactly one node before the target - perfectly positioned to skip it with slow.next = slow.next.next. The dummy node before head ensures this works even when removing the head node itself.
Core Concept
Create dummy node pointing to head. Initialise fast = slow = dummy. Advance fast exactly n+1 times. Then advance both until fast is null. Now slow.next is the nth-from-end node. Execute slow.next = slow.next.next. Return dummy.next. The n+1 offset (not n) is critical: it lands slow at the predecessor of the target, not the target itself. Time: O(L), Space: O(1).
When to use
Any "kth from end" problem on linked lists; also a sub-pattern when you need to position a pointer relative to the list tail in one pass.
When NOT to use
When the list is doubly linked (can traverse backwards). When n is guaranteed to equal the list length - just return head.next.
Key Insights
What to Know Cold
- Advance fast n+1 steps (not n) so slow lands at the predecessor of the target, enabling deletion.
- Dummy node before head unifies the edge case of removing the head - no special-casing needed.
- Both pointers start from dummy, not head - keeps the offset math consistent.
- n is guaranteed valid (1 ≤ n ≤ length) per constraints, so no bounds check needed.
- Alternative: two-pass approach - count length, then advance (L-n) steps. O(L) but two passes.
1 example
Worked Examples
Remove 2nd from end of 5-node list
[1,2,3,4,5] n=2 → remove node 4
Dummy + n+1 gap between fast and slow
function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
const dummy = new ListNode(0, head);
let fast: ListNode | null = dummy, slow: ListNode | null = dummy;
for (let i = 0; i <= n; i++) fast = fast!.next;
while (fast) { slow = slow!.next; fast = fast.next; }
slow!.next = slow!.next!.next;
return dummy.next;
}Output: [1,2,3,5]
Classic one-pass gap technique - also used to find kth-from-end node in general.