Remove Nth Node From End of List medium
Problem Statement
Given the head
of a linked list, remove the nth node from the end of the list and return its head.
Example 1:
Input: head = [1,2,3,4,5], n = 2 Output: [1,2,3,5]
Example 2:
Input: head = [1], n = 1 Output: []
Steps:
- Two-Pointer Approach: We'll use two pointers,
fast
andslow
. - Initial Setup: Initially, both
fast
andslow
point to the head of the list. - Gap Creation: Move the
fast
pointern
steps forward. This creates a gap ofn
nodes betweenfast
andslow
. - Simultaneous Movement: Move both
fast
andslow
pointers one step at a time untilfast
reaches the end of the list (i.e.,fast.next
is null). At this point,slow
will be pointing to the node before the nth node from the end. - Removal: Remove the nth node from the end by updating the
slow.next
pointer to skip over the node to be removed. - Edge Cases: Handle edge cases such as an empty list or when
n
is greater than or equal to the length of the list.
Explanation:
The key idea is to use the two-pointer technique to efficiently find the node before the nth node from the end. By creating an initial gap of n
nodes between fast
and slow
, and then moving them simultaneously, we ensure that when fast
reaches the end, slow
is in the correct position to remove the desired node.
Consider Example 1 ([1,2,3,4,5], n=2):
fast
andslow
start at node 1.fast
moves 2 steps ahead to node 3.fast
andslow
move together untilfast
reaches the end (node 5). At this point:fast
points to node 5.slow
points to node 3.
slow.next
(which points to node 4) is updated to point tofast.next
(node 5), effectively removing node 4.
Code:
class ListNode {
val: number;
next: ListNode | null;
constructor(val?: number, next?: ListNode | null) {
this.val = (val===undefined ? 0 : val)
this.next = (next===undefined ? null : next)
}
}
function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
if (head === null) return null; //Handle empty list
let dummy = new ListNode(0, head); //Add a dummy node to simplify edge cases
let fast = dummy;
let slow = dummy;
//Move fast pointer n steps ahead
for (let i = 0; i <= n; i++) {
fast = fast.next!; // ! is used since we checked for empty list, fast.next will always exist in loop
}
//Move both pointers until fast reaches the end
while (fast !== null) {
fast = fast.next;
slow = slow.next!;
}
//Remove the nth node from the end
slow.next = slow.next!.next;
return dummy.next; //Return the head of the list (after dummy node)
}
Complexity:
- Time Complexity: O(L), where L is the length of the linked list. We traverse the list once with each pointer.
- Space Complexity: O(1). We use only a constant amount of extra space for the pointers.