Remove Nth Node from End of List in DSA C++ - Time & Space Complexity
We want to understand how the time needed to remove the nth node from the end of a linked list changes as the list grows.
How does the number of steps grow when the list gets longer?
Analyze the time complexity of the following code snippet.
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* fast = dummy;
ListNode* slow = dummy;
for (int i = 0; i < n; i++) {
fast = fast->next;
}
while (fast->next) {
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return dummy->next;
}
This code removes the nth node from the end by using two pointers moving through the list.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Two pointer traversals through the linked list.
- How many times: The first loop moves the fast pointer n steps; the second loop moves both pointers until fast reaches the end, roughly (length - n) steps.
As the list size grows, the number of steps grows roughly in a straight line with the list length.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps |
| 100 | About 100 steps |
| 1000 | About 1000 steps |
Pattern observation: The steps increase directly with the list size, so doubling the list roughly doubles the work.
Time Complexity: O(n)
This means the time to remove the nth node from the end grows linearly with the size of the list.
[X] Wrong: "Since we only move the fast pointer n steps first, the time is O(n) where n is the position from the end, not the list length."
[OK] Correct: Because after moving fast n steps, we still move both pointers through the rest of the list, which depends on the total list length, not just n.
Understanding this linear time approach shows you can efficiently handle linked list problems using two pointers, a common and useful skill in coding challenges.
"What if we used a single pass with extra memory to store nodes? How would the time complexity change?"
Practice
Solution
Step 1: Understand the problem statement
The problem asks to remove the node that is Nth from the end of the linked list, not from the start or to reverse or add nodes.Step 2: Clarify the operation on the list
Removing the Nth node from the end means counting nodes from the tail backwards and deleting that node.Final Answer:
Remove the node that is Nth from the end of the list -> Option DQuick Check:
Remove Nth from end = Remove Nth from end [OK]
- Confusing Nth from end with Nth from start
- Thinking the problem asks to reverse the list
- Trying to add nodes instead of removing
Solution
Step 1: Check parameter order and types
The function should take the head pointer of the list and the integer n as parameters, with head first and n second.Step 2: Check return type
Since the head might change (if first node is removed), the function returns a pointer to the new head.Final Answer:
ListNode* removeNthFromEnd(ListNode* head, int n); -> Option AQuick Check:
Correct signature = ListNode* removeNthFromEnd(ListNode* head, int n); [OK]
- Wrong parameter order
- Returning ListNode instead of pointer
- Missing head parameter
Solution
Step 1: Identify the 2nd node from the end
Counting from the end: 5 (1st), 4 (2nd). So node with value 4 is to be removed.Step 2: Remove node 4 and link previous node to next
Node 3's next pointer now points to node 5, skipping node 4.Final Answer:
1 -> 2 -> 3 -> 5 -> null -> Option AQuick Check:
Remove 2nd from end = Remove node 4 [OK]
- Removing wrong node counting from start
- Not updating links correctly
- Confusing 2nd from end with 2nd from start
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* fast = head;
ListNode* slow = head;
for (int i = 0; i < n; i++) {
fast = fast->next;
}
while (fast->next != nullptr) {
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return head;
}Solution
Step 1: Analyze fast pointer movement
Fast pointer moves n steps ahead. If n equals list length, fast becomes nullptr.Step 2: Check while loop condition
While loop uses fast->next, but if fast is nullptr, accessing fast->next causes error. Also, removing head node is not handled.Final Answer:
Does not handle case when n equals list length (removing head) -> Option BQuick Check:
Edge case for head removal missing [OK]
- Ignoring removal of head node
- Accessing fast->next without null check
- Not updating head pointer when needed
Solution
Step 1: Initialize two pointers at head
Start both fast and slow pointers at the head of the list.Step 2: Move fast pointer n steps ahead
Move fast pointer 3 steps ahead to create a gap of 3 nodes between fast and slow.Step 3: Move both pointers until fast reaches end
Move fast and slow pointers one step at a time until fast reaches the last node.Step 4: Remove the node after slow pointer
Slow pointer now points to node before the target; remove slow->next node.Final Answer:
Move fast pointer 3 steps ahead, then move both pointers until fast reaches end, then remove slow's next node. -> Option CQuick Check:
Two-pointer gap method = Move fast pointer 3 steps ahead, then move both pointers until fast reaches end, then remove slow's next node. [OK]
- Moving slow pointer first instead of fast
- Removing wrong node after pointers move
- Not creating correct gap between pointers
Ready to prove it?
Pass the test and this pattern moves unknown
