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.
struct ListNode {
int val;
struct ListNode *next;
};
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
struct ListNode *fast = head, *slow = head;
for (int 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;
}
This code removes the nth node from the end of a singly linked list using two pointers.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Two loops: one moves the fast pointer n steps, the other moves both pointers until fast reaches the end.
- How many times: The first loop runs n times; the second loop runs (length - n) times, where length is the total nodes in the list.
As the list length grows, the total steps grow roughly in a straight line with the list size.
| Input Size (length) | Approx. Operations |
|---|---|
| 10 | About 10 steps to move fast + up to 9 steps to move slow and fast = ~19 steps |
| 100 | About 100 steps total |
| 1000 | About 1000 steps total |
Pattern observation: The number of steps grows roughly in direct proportion to the list size.
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: "Because we only move the fast pointer n steps first, the time complexity is O(n) where n is the position from the end, not the list length."
[OK] Correct: The second loop moves through the rest of the list, which depends on the total list length, so the overall time depends on the full list size, not just n.
Understanding this linear time approach shows you can efficiently handle linked list problems without extra space, a skill often valued in coding challenges.
"What if we used a single pass approach without two pointers? How would the time complexity change?"
Practice
Solution
Step 1: Understand the problem statement
The problem requires removing the node that is exactly N positions from the end of the linked list.Step 2: Clarify the difference from other options
Options A, C, and D describe different operations: removing from start, adding nodes, or reversing, which are not asked here.Final Answer:
Remove the node that is Nth from the end of the list -> Option AQuick Check:
Remove Nth from end = Remove the node that is Nth from the end of the list [OK]
- Confusing Nth from start with Nth from end
- Thinking the problem asks to add nodes
- Assuming the list needs reversing
Solution
Step 1: Recall C struct pointer syntax
In C, to declare a pointer to a struct Node, use 'struct Node* head;'.Step 2: Identify incorrect syntax
Options A, B, and D misuse the order or omit 'struct' keyword which is required unless typedef is used.Final Answer:
struct Node* head; -> Option CQuick Check:
Pointer to struct Node = struct Node* head; [OK]
- Omitting 'struct' keyword in declaration
- Placing '*' incorrectly after variable name
- Using typedef name without defining it
Solution
Step 1: Identify the 2nd node from the end
The list is 1->2->3->4->5. Counting from end: 5 (1st), 4 (2nd). So node with value 4 is to be removed.Step 2: Remove node with value 4 and link previous to next
After removal, the list becomes 1->2->3->5->null.Final Answer:
1 -> 2 -> 3 -> 5 -> null -> Option DQuick Check:
Remove 2nd from end (4) = 1->2->3->5->null [OK]
- Removing the wrong node counting from start
- Skipping the link update after removal
- Confusing 2nd from end with 2nd from start
struct Node* removeNthFromEnd(struct Node* head, int n) {
struct Node* fast = head;
struct Node* slow = head;
for (int i = 0; i < n; i++) {
fast = fast->next;
}
while (fast->next != NULL) {
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return head;
}Solution
Step 1: Analyze the for loop moving fast pointer
The loop moves fast pointer n times without checking if fast is NULL, which can cause a crash if n is larger than list length.Step 2: Check while loop condition and pointer usage
The while loop uses fast->next without null check before the loop, which is unsafe if fast is NULL.Final Answer:
The loop does not check if fast becomes NULL before accessing fast->next -> Option BQuick Check:
Missing NULL check on fast pointer causes error [OK]
- Not checking if fast is NULL before fast->next
- Assuming list length is always >= n
- Ignoring edge case when removing head node
Solution
Step 1: Identify the 5th node from the end
The list length is 5, so the 5th node from the end is the first node with value 10.Step 2: Remove the head node and update head pointer
Removing the first node results in the list: 20 -> 30 -> 40 -> 50 -> null.Final Answer:
20 -> 30 -> 40 -> 50 -> null -> Option AQuick Check:
Remove 5th from end (head) = list without first node [OK]
- Not updating head pointer when removing first node
- Confusing Nth from end with Nth from start
- Assuming no change if N equals list length
Ready to prove it?
Pass the test and this pattern moves unknown
