Problem Description
Given the head of a linked list, remove the nth node from the end of the list and return its head.
Examples
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]
Python Solution
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
def removeNthFromEnd(head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy = ListNode(0)
dummy.next = head
first = dummy
second = dummy
# Advance first pointer by n + 1 steps
for i in range(n + 1):
first = first.next
# Move both pointers until first reaches the end
while first:
first = first.next
second = second.next
# Remove the nth node
second.next = second.next.next
return dummy.next
Java Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode first = dummy;
ListNode second = dummy;
// Advance first pointer by n + 1 steps
for (int i = 0; i < n + 1; i++) {
first = first.next;
}
// Move both pointers until first reaches the end
while (first != null) {
first = first.next;
second = second.next;
}
// Remove the nth node
second.next = second.next.next;
return dummy.next;
}
}
C++ Solution
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* first = dummy;
ListNode* second = dummy;
// Advance first pointer by n + 1 steps
for (int i = 0; i < n + 1; i++) {
first = first->next;
}
// Move both pointers until first reaches the end
while (first != nullptr) {
first = first->next;
second = second->next;
}
// Remove the nth node
ListNode* temp = second->next;
second->next = second->next->next;
delete temp;
ListNode* result = dummy->next;
delete dummy;
return result;
}
};
JavaScript Solution
/**
* 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) {
const dummy = new ListNode(0);
dummy.next = head;
let first = dummy;
let second = dummy;
// Advance first pointer by n + 1 steps
for (let i = 0; i < n + 1; i++) {
first = first.next;
}
// Move both pointers until first reaches the end
while (first !== null) {
first = first.next;
second = second.next;
}
// Remove the nth node
second.next = second.next.next;
return dummy.next;
};
C# Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int val=0, ListNode next=null) {
* this.val = val;
* this.next = next;
* }
* }
*/
public class Solution {
public ListNode RemoveNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode first = dummy;
ListNode second = dummy;
// Advance first pointer by n + 1 steps
for (int i = 0; i < n + 1; i++) {
first = first.next;
}
// Move both pointers until first reaches the end
while (first != null) {
first = first.next;
second = second.next;
}
// Remove the nth node
second.next = second.next.next;
return dummy.next;
}
}
Complexity Analysis
- Time Complexity: O(L) where L is the length of the linked list
- Space Complexity: O(1) as we only use two pointers
Solution Explanation
This solution uses the two-pointer technique. Here's how it works:
- Create a dummy node to handle edge cases
- Use two pointers: first and second
- Move first pointer:
- Advance it by n+1 steps ahead
- This creates a gap of n nodes between first and second
- Move both pointers until first reaches the end
- Remove the nth node from the end
Key points:
- Dummy node helps handle edge cases like removing first node
- Two-pointer technique avoids counting the length of list
- The solution handles all edge cases properly
- Memory is managed properly in languages like C++