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:
- The number of nodes in the list is
sz
. 1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
Problem Description
The problem presents us with a linked list and requires us to remove the nth node from the end of the list. A linked list is a linear collection of elements called nodes, where each node contains data and a reference (or link) to the next node in the sequence. The head
of a linked list refers to the first node in this sequence. Our goal is to remove the nth node from the last node and return the updated list’s head
.
In simple terms, if we were to count nodes starting from the last node back to the first, we need to find and remove the node that sits at position ‘n’. For example, if the linked list is 1->2->3->4->5
and n
is 2, the resulting linked list after the operation should be 1->2->3->5
, since the 4
is the 2nd node from the end.
The challenge with this task is that we can’t navigate backwards in a singly linked list, so we need to figure out a way to reach the nth node from the end only by moving forward.
Intuition
To address the problem, we apply a two-pointer approach, which is a common technique in linked list problems. The intuition here lies in maintaining two pointers that we’ll call fast
and slow
. Initially, both of these pointers will start at a dummy node that we create at the beginning of the list, which is an auxiliary node to simplify edge cases, such as when the list contains only one node, or when we need to remove the first node of the list.
The fast
pointer advances n
nodes into the list first. Then, both slow
and fast
pointers move at the same pace until fast
reaches the end of the list. At this point, slow
will be right before the node we want to remove. By updating the next
reference of the slow
pointer to skip the target node, we effectively remove the nth node from the end of the list.
The use of a dummy node is a clever trick to avoid having to separately handle the special case where the node to remove is the first node of the list. By ensuring that our slow
pointer starts before the head
of the actual list, we can use the same logic for removing the nth node, regardless of its position in the list.
After we’ve completed the removal, we return dummy.next
, which is the updated list’s head
, after the dummy node.
Solution Approach
The solution implements an efficient approach to solving the problem by using two pointers and a dummy node. Here’s a step-by-step walkthrough of the implementation:
- Create a Dummy Node: A dummy node is created and its
next
pointer is set to thehead
of the list. This dummy node serves as an anchor and helps to simplify the removal process, especially if thehead
needs to be removed.dummy = ListNode(next=head)
- Initialize Two Pointers: Two pointers
fast
andslow
are introduced and both are set to the dummy node. This allows for them to start from the very beginning of the augmented list (which includes the dummy node).fast = slow = dummy
- Advance Fast Pointer: The
fast
pointer advancesn
steps into the list.for _ in range(n): fast = fast.next
- Move Both Pointers: Both pointers then move together one step at a time until the
fast
pointer reaches the end of the list. By this time,slow
is at the position right before the nth node from the end.while fast.next: slow, fast = slow.next, fast.next
- Remove the Target Node: Once
slow
is in position, itsnext
pointer is changed to skip the target node which effectively removes it from the list.slow.next = slow.next.next
- Return Updated List: Finally, the next node after the dummy is returned as the new head of the updated list.
return dummy.next
The algorithm fundamentally relies on the two-pointer technique to find the nth node from the end. The use of a dummy node facilitates the removal of nodes, including the edge case of the head
node, with a consistent method. The space complexity is O(1) since no additional space is required aside from the pointers, and the time complexity is O(L), where L is the length of the list, as we traverse the list with two pointers in a single pass.
Example Walkthrough
Let’s use the linked list 1->2->3->4->5
as an example to illustrate the solution approach described above, where n
is 2, meaning we want to remove the 2nd node from the end, which is the node with the value 4
. Here’s how the algorithm would be applied:
- Create a Dummy Node: We create a dummy node with
None
as its value and link it to the head of our list. Our list now looks likedummy->1->2->3->4->5
. - Initialize Two Pointers: We set both
fast
andslow
pointers to the dummy node. They both point todummy
initially. - Advance Fast Pointer: As
n
is 2, we advance thefast
pointern
steps into the list.fast
becomes:- After 1st step:
fast
points to1
- After 2nd step:
fast
points to2
- After 1st step:
- Move Both Pointers: Now we move both
slow
andfast
pointers together one step at a time untilfast
reaches the last node:slow
points todummy
andfast
points to2
(Start)slow
points to1
andfast
points to3
slow
points to2
andfast
points to4
slow
points to3
andfast
points to5
(End)
slow
points to the3
andfast
points to the last node5
. - Remove the Target Node: Now,
slow.next
is pointing to the node4
, which we want to remove. We updateslow.next
to point toslow.next.next
(which is5
), effectively removing the4
from the list. - Return Updated List: Finally, we return the next node after the dummy, which is the
head
of our updated list (1->2->3->5
). The updated list after removal is as follows:1->2->3->5
.
The problem is solved in one pass and the node is successfully removed according to the given constraints.
Solution Implementation
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *prev;
ListNode *dummy = new ListNode();
dummy->next = head;
prev = dummy;
int t = 0;
while(prev != NULL){
prev = prev->next;
t++;
}
if(t == 1){
head = NULL;
return head;
}
prev = dummy;
t = t - n;
for(int i = 0; i<t-1; i++){
prev = prev->next;
}
prev->next = prev->next->next;
return dummy->next;
}
};
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
// Creating a dummy node to simplify the removal of head
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode slow = dummy;
ListNode fast = dummy;
// 1. Move fast n+1 step forward so that slow is in front of the node being deleted
for (int i = 0; i <= n; i++) {
fast = fast.next;
}
// 2. Move fast to the end, and slow to the node before the deleted one
while (fast != null) {
slow = slow.next;
fast = fast.next;
}
// 3. Remove the nth node from the end (slow.next points to it)
slow.next = slow.next.next;
// Returning a new head (dummy.next could have changed if the head was deleted)
return dummy.next;
}
}
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
count = 0
curr = head
dummy = curr
while curr:
count += 1
curr = curr.next
# if count == 1 and n == 1:
# return None
if count == n:
head = head.next
remove = count - n
count = 0
while dummy:
count +=1
if count == remove:
dummy.next = dummy.next.next
break
dummy = dummy.next
return head
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
struct ListNode* temp=head;
int count=0;
while(temp!=NULL){
temp=temp->next;
count=count+1;
}
if (count == n) {
struct ListNode* newHead = head->next;
free(head);
return newHead;
}
struct ListNode* tempa=head;
for(int i=0;i<count-n-1;i++){
tempa=tempa->next;
}
struct ListNode* tem=tempa->next;
tempa->next=tempa->next->next;
free(tem);
return head;
}
public class Solution {
public ListNode RemoveNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode fast = dummy;
ListNode slow = dummy;
// Move fast pointer n+1 steps ahead
for (int i = 0; i <= n; i++) {
fast = fast.next;
}
// 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;
}
}
var removeNthFromEnd = function(head, n) {
let fast = head, slow = head
for (let i = 0; i < n; i++) fast = fast.next
if (!fast) return head.next
while (fast.next) fast = fast.next, slow = slow.next
slow.next = slow.next.next
return head
};
// We assume ListNode is provided by the environment and should not be redefined.
function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
// Create a dummy node to simplify edge cases
const dummy = new ListNode(0);
dummy.next = head;
let first: ListNode | null = dummy;
let second: ListNode | null = dummy;
// Move the first pointer n+1 steps ahead
for (let i = 0; i <= n; i++) {
first = first?.next ?? null;
}
// Move both pointers until the first pointer reaches the end
while (first !== null) {
first = first.next;
second = second?.next ?? null;
}
// Remove the nth node from the end
second!.next = second?.next?.next ?? null;
// Return the new head of the list
return dummy.next;
}
class Solution {
/**
* @param ListNode $head
* @param Integer $n
* @return ListNode
*/
function removeNthFromEnd($head, $n) {
$dummy = new ListNode(0, $head);
$first = $dummy;
$second = $dummy;
for ($i = 0; $i <= $n; $i++) {
$first = $first->next;
}
while ($first !== null) {
$first = $first->next;
$second = $second->next;
}
$second->next = $second->next->next;
return $dummy->next;
}
}
class Solution {
func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
let node = ListNode(0)
node.next = head
var prev: ListNode? = node
var post: ListNode? = node
for _ in 0..<n {
guard let next = post?.next else { continue }
post = next
}
while let postNext = post?.next, let prevNext = prev?.next {
prev = prevNext
post = postNext
}
prev!.next = prev!.next!.next
return node.next
}
}
class Solution {
fun removeNthFromEnd(head: ListNode, n: Int): ListNode? {
head0.next = head
var node: ListNode? = head0
var steps = getNodeCount(head0) - n
while (steps > 1) {
steps--
node = node?.next
}
node?.next = node?.next?.next
return head0.next
}
private fun getNodeCount(head: ListNode): Int {
var count = 0
var node: ListNode? = head
while (node != null) {
node = node.next
count++
}
return count
}
companion object {
val head0 = ListNode(0)
}
}
class Solution {
ListNode? removeNthFromEnd(ListNode? head, int n) {
final dummy = ListNode(0, head);
ListNode? left = dummy;
ListNode? right = head;
while(n > 0 && right != null) {
right = right.next;
n--;
}
while(right != null) {
right = right.next;
left = left?.next;
}
left?.next = left.next?.next;
return dummy.next;
}
}
func removeNthFromEnd(head *ListNode, n int) *ListNode {
// Создаем фиктивный узел перед головным узлом
dummy := &ListNode{0, head}
slow, fast := dummy, dummy
// Перемещаем fast на n+1 шаг вперед
for i := 0; i <= n; i++ {
fast = fast.Next
}
// Двигаем slow и fast одновременно
for fast != nil {
slow = slow.Next
fast = fast.Next
}
// Удаляем узел, на который указывает slow.Next
slow.Next = slow.Next.Next
// Возвращаем обновленный список, пропуская фиктивный узел
return dummy.Next
}
Time and Space Complexity
The given code is designed to remove the nth node from the end of a singly linked list. It employs the two-pointer technique with fast
and slow
pointers. Let’s analyze the time and space complexity:
Time Complexity
The time complexity is determined by the number of operations required to traverse the linked list. There are two main steps in this algorithm:
- The
fast
pointer movesn
steps ahead – this takesO(n)
time. - Both
fast
andslow
pointers move together untilfast
reaches the last node. The worst-case scenario is whenn
is 1, which would cause theslow
pointer to traverse the entire list of sizeL
(list length), takingO(L)
time.
Since the list is traversed at most once, the overall time complexity is O(L)
.
Space Complexity
The space complexity is determined by the amount of additional space used by the algorithm, which does not depend on the input size:
- The
dummy
node and the pointers (fast
andslow
) use constant extra space, regardless of the linked list’s size. - Therefore, the space complexity is
O(1)
for the extra space used by the pointers and the dummy node.
Sir plese solve the problem 🙏