Remove the Nth Node from the End
Table of Contents + β
This one looks small. But it traps a lot of people. The interviewer hands you a linked list and says βdelete the nth node, but count from the end.β So now you have a problem. In a singly linked list you can only walk forward. You cannot jump to the end and count backward. So how do you find a node from the back when you can only move from the front? That is the real thing being tested here. Can you turn βfrom the endβ into βfrom the frontβ without walking the list twice?
π The Problem
You are given the head of a singly linked list and a number n. You have to remove the node that is the nth one counting from the end. Then return the head of the changed list.
Here n counts from the back. So n = 1 means the last node. And n = 2 means the second-to-last node. And so on.
Input: 1 -> 2 -> 3 -> 4 -> 5, n = 2Output: 1 -> 2 -> 3 -> 5
We removed node 4, because 4 is the 2nd node from the end.To delete a node in a singly linked list, you do not touch the node itself. You change the next pointer of the node before it. So the real job is to stop at the node just before the one you want to remove.
π’ The Simple Approach: Count First, Then Delete
The first idea that comes to mind is simple. Walk the whole list once and count how many nodes there are. Say the length is L. The nth node from the end is the (L - n)th node from the front. So now you walk again from the front and stop right before it. Then you fix the pointer.
This works fine. It gives the right answer. But see, you walked the list two times. Once to count. Once to delete. The interviewer will almost always smile and ask, βCan you do it in one pass?β That is the hint that they want something better.
π The Optimal Approach: Two Pointers with a Gap
Here is the trick. We use two pointers. And we keep a fixed gap between them.
Think of two people walking on the same road. Riya starts first. She walks n steps ahead. Then Arjun starts from the beginning. Now both walk at the same speed, one step at a time. The gap between them stays exactly n the whole time. So when Riya reaches the very end, Arjun is sitting exactly n nodes behind the end. That is exactly the spot we care about.
We want to stop Arjun just before the node to delete. So we make the gap a little bigger and start Arjun from a fake node. This fake node is called a dummy head. It is an extra node we place before the real head. Why do we need it? Because what if you have to delete the first node itself? Then there is no node before it. The dummy head gives us a safe node to stand on. So the same code works even for the head.
Here n is assumed to be valid. That means it is between 1 and the length of the list.
Steps to do it in one pass:
- Create a dummy node and point its
nextto the head. Set bothfastandslowto this dummy node. - Move
fastforward bynsteps. Now there is a gap ofnbetweenfastandslow. - Move both
fastandslowone step at a time untilfastreaches the last node (itsnextis null). - Now
slowis sitting right before the node to remove. Setslow.next = slow.next.nextto skip over it. - Return
dummy.nextas the new head.
class Node: def __init__(self, value): self.data = value self.next = None
# Remove the nth node from the end in one passdef remove_nth_from_end(head, n): dummy = Node(0) # dummy head dummy.next = head fast = dummy slow = dummy
# Move fast n steps ahead so the gap becomes n for _ in range(n): fast = fast.next
# Move both until fast is at the last node while fast.next is not None: fast = fast.next slow = slow.next
# slow is right before the target; skip the target slow.next = slow.next.next
return dummy.next
def print_list(head): parts = [] while head is not None: parts.append(str(head.data)) head = head.next print(" -> ".join(parts))
# Build 1 -> 2 -> 3 -> 4 -> 5head = Node(1)head.next = Node(2)head.next.next = Node(3)head.next.next.next = Node(4)head.next.next.next.next = Node(5)
head = remove_nth_from_end(head, 2)print_list(head)The output of the above code will be:
1 -> 2 -> 3 -> 5β±οΈ Time and Space Complexity
Both approaches walk a constant number of times. So both are O(n) in time. The real difference is the number of passes. The two-pointer way does it in a single pass. That is the version the interviewer wants to see.
| Approach | Passes | Time | Space |
|---|---|---|---|
| Count first, then delete | Two | O(n) | O(1) |
| Two pointers with a gap | One | O(n) | O(1) |
Tip
The dummy head is the part people forget. Without it, deleting the first node crashes, because slow has no node to stand on before the head. When the interviewer gives an edge case like βthe list has one node and n = 1β, the dummy head makes your code just work. Mention it out loud and you score points.
π§© Key Takeaways
- β
βNth from the endβ becomes βnth from the frontβ once you keep a fixed gap of
nbetween two pointers. - β
Move the
fastpointernsteps ahead first. Then move both together untilfasthits the last node. - β A dummy head before the real head lets the same code delete the first node safely.
- β
You delete a node by changing the
nextof the node before it. So always stop at the node before the target. - β This runs in one pass: O(n) time and O(1) extra space.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
Why do we use a dummy node before the head?
Why: The dummy gives slow a node to stand on before the head, so removing the first node needs no special case.
- 2
After moving fast n steps ahead, what is true when fast reaches the last node?
Why: The gap of n stays fixed, so when fast is at the end, slow sits just before the target node.
- 3
How do you actually remove the target node in a singly linked list?
Why: You change the previous node's next pointer so it points past the target, skipping it.
- 4
What is the time and space complexity of the two-pointer solution?
Why: It does a single pass over the list and uses only a couple of pointers.