Linked list dashed node = dummy before head · right (blue) runs n nodes ahead of left · row 2 = the unlinked node
public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(0, head); ListNode left = dummy; ListNode right = head; while (n > 0) { // open a gap of n nodes right = right.next; n--; } while (right != null) { // slide the gap to the end left = left.next; right = right.next; } left.next = left.next.next; // skip the target return dummy.next;}
- n
- —
- left
- —
- right
- —
- list
- —
Why it works
- Brute force walks twice: count the length L, then walk L − n nodes and unlink the next one. Still O(L), but two passes; the follow-up asks for one.
- Keep a fixed gap.
rightstarts n nodes ahead ofleft, and both move together. Whenrightfalls off the end (null),leftis exactly n + 1 nodes from it: the node just before the target. - One pass, two pointers:
rightvisits every node once andlefttrails it, so O(L) time and O(1) space. - Pitfall: removing the head. When n equals the length, the target has no predecessor. The dummy node gives it one, so
left.next = left.next.nextworks with no special case. Returndummy.next, nothead, which may be the removed node. - Pitfall: the gap is n, not n − 1.
leftstarts on the dummy, one step behindhead, so it stops on the predecessor instead of the target itself.