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: []
Example 3:
Input: head = [1,2], n = 1 Output: [1]
Constraints:
sz
.1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
Follow up: Could you do this in one pass?
The core challenge of this problem is to remove the nth node from the end of a singly linked list in an efficient manner. This problem is significant in many real-world applications, such as managing playlists, task lists, or any other sequential data structure where elements need to be dynamically removed.
Potential pitfalls include off-by-one errors and handling edge cases such as removing the first or last node in the list.
To solve this problem, we can use a two-pointer technique to achieve a one-pass solution. The idea is to maintain two pointers that are n nodes apart. When the second pointer reaches the end of the list, the first pointer will be at the node just before the one we need to remove.
Here is a step-by-step approach:
Let's break down the algorithm step-by-step:
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
// Create a dummy node that points to the head
let dummy = new ListNode(0);
dummy.next = head;
// Initialize two pointers, both starting at the dummy node
let first = dummy;
let second = dummy;
// Move the second pointer n+1 steps ahead
for (let i = 0; i <= n; i++) {
second = second.next;
}
// Move both pointers until the second pointer reaches the end
while (second !== null) {
first = first.next;
second = second.next;
}
// Adjust the next pointer of the first pointer to skip the target node
first.next = first.next.next;
// Return the head of the modified list
return dummy.next;
};
The time complexity of this approach is O(n), where n is the number of nodes in the list. This is because we traverse the list with the second pointer and then again with both pointers. The space complexity is O(1) as we are using only a constant amount of extra space.
Some potential edge cases include:
Our algorithm handles these cases by using a dummy node and adjusting pointers accordingly.
To test the solution comprehensively, consider the following test cases:
head = [1,2,3,4,5], n = 2 => [1,2,3,5] head = [1], n = 1 => [] head = [1,2], n = 1 => [1] head = [1,2], n = 2 => [2]
Use a testing framework like Jest or Mocha to automate these tests and ensure the correctness of the solution.
When approaching such problems, consider the following tips:
In this blog post, we discussed how to remove the nth node from the end of a linked list using a two-pointer technique. We covered the problem definition, approach, algorithm, code implementation, complexity analysis, edge cases, and testing. Understanding and solving such problems is crucial for improving your algorithmic thinking and coding skills.
For further reading and practice, consider the following resources: