Remove Nth Node From End of List
You are given the head of a singly linked list and an integer n. Delete the node that is n-th when counting from the end of the list (the last node is 1st from the end, the one before it is 2nd, and so on), then return the head of the resulting list.
The list is shown as an array of its values from head to tail, e.g. [10, 20, 30]. If the head itself is removed, return the new first node, or null if the list becomes empty.
Can you do it in a single pass over the list?
Example 1
Example 2
Example 3
Constraints
The number of nodesszsatisfies 1 <= sz <= 104-106 <= Node.val <= 1061 <= n <= sz
Pattern Path · Linked Lists · problem 71 of 169
n nodes apart. When the front one falls off the end, where is the back one?Start simple
Count the length L in one pass, then walk L - n steps to the predecessor and unlink it: O(L) time but two passes.
The key idea
To delete a node in a singly linked list you need its predecessor, so the real task is to stop one node before the target. Two pointers with a fixed gap give you that in a single pass.
Create a dummy node whose next is the head, and set fast and slow to the dummy. Move fast forward n steps. Now move both together until fast.next is null, i.e. fast sits on the last node. The gap between them is still n, so slow is exactly n nodes before the last node: it is the predecessor of the n-th node from the end. Unlink with slow.next = slow.next.next and return dummy.next.
The dummy node is what makes removing the head painless: in that case slow never moves, and dummy.next automatically becomes the second node.
Complexity
- Time:
O(L) - Space:
O(1)
Python
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy = ListNode(0, head)
fast = slow = dummy
for _ in range(n): # open a gap of n nodes
fast = fast.next
while fast.next: # when fast is on the last node, slow is just before the target
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return dummy.next
JavaScript
var removeNthFromEnd = function(head, n) {
const dummy = new ListNode(0, head);
let fast = dummy, slow = dummy;
for (let i = 0; i < n; i++) fast = fast.next; // open a gap of n nodes
while (fast.next) { // when fast is on the last node, slow is just before the target
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummy.next;
};
What the interviewer is checking
The interviewer is checking the two-pointer gap trick and careful pointer handling, especially the head-removal edge case that a dummy node solves.
Mistakes to avoid
- Returning the original
headwhen the head itself was removed. - Off-by-one in the gap: stopping on the target instead of its predecessor.
- Dereferencing
nullwhen n equals the list length and no dummy node is used.
Follow-ups to expect
- Return the n-th node from the end without deleting it. (Same gap, stop on target.)
- What if n could be larger than the length? (Detect fast hitting null early.)
- Find the middle node in one pass. (Fast moves two steps, slow one.)
In real software
Bounded history buffers and undo stacks often drop "the k-th most recent entry", and the fixed-gap pointer idea is how streaming systems track a trailing window without knowing the total length.