Remove Nth Node from End of List in DSA Java - 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.
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode fast = head;
ListNode slow = head;
for (int i = 0; i < n; i++) {
fast = fast.next;
}
if (fast == null) return head.next;
while (fast.next != null) {
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 by using two pointers moving through the list.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Moving pointers through the linked list nodes.
- How many times: The first loop moves the fast pointer n times; the second loop moves both pointers until fast reaches the end, which can be up to (length - n) times.
As the list size grows, the number of steps to move pointers grows roughly in proportion to the list length.
| Input Size (length) | Approx. Operations |
|---|---|
| 10 | About 10 steps to move pointers |
| 100 | About 100 steps to move pointers |
| 1000 | About 1000 steps to move pointers |
Pattern observation: The steps increase linearly as the list gets longer.
Time Complexity: O(n)
This means the time to remove the nth node from the end grows in a straight line with the size of the list.
[X] Wrong: "Since we only move the fast pointer n times first, the time is O(n) where n is the position from the end, so it is always small."
[OK] Correct: The second loop moves the pointers through the rest of the list, which depends on the total list length, not just n. So the total time depends on the full list size.
Understanding this helps you explain how to efficiently handle linked lists with two pointers, a common pattern in coding problems.
"What if we used a single pass 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 Nth from the end of the linked list, not from the start.Step 2: Clarify the operation on the list
We do not add or reverse nodes; we specifically remove one node counting from the end.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 add or reverse nodes
- Ignoring the direction of counting nodes
Solution
Step 1: Check method parameters and return type
The method should take the head of the list and an integer n, and return the new head after removal.Step 2: Match signature with problem requirements
public ListNode removeNthFromEnd(ListNode head, int n) matches the expected signature: it takes (ListNode head, int n) and returns ListNode.Final Answer:
public ListNode removeNthFromEnd(ListNode head, int n) -> Option AQuick Check:
Correct signature = public ListNode removeNthFromEnd(ListNode head, int n) [OK]
- Wrong parameter order
- Void return type instead of ListNode
- Using incorrect parameter types
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 with value 4 and link previous node to next
After removal, list becomes 1 -> 2 -> 3 -> 5 -> null.Final Answer:
1 -> 2 -> 3 -> 5 -> null -> Option BQuick Check:
Remove 2nd from end = Remove node 4 [OK]
- Removing wrong node counting from start
- Off-by-one errors in counting
- Not updating links correctly after removal
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode fast = head;
ListNode slow = head;
for (int i = 0; i <= n; i++) {
fast = fast.next;
}
while (fast != null) {
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return head;
}Solution
Step 1: Analyze the for loop for moving fast pointer
The loop runs i from 0 to n inclusive (i <= n), moving fast n+1 steps, which is one step too many and causes NullPointerException.Step 2: Correct the loop to run i < n to move fast exactly n steps ahead
This ensures fast is n nodes ahead of slow, allowing correct removal of the target node.Final Answer:
The for loop should run from i = 0 to i < n, not i <= n -> Option AQuick Check:
Loop count off by one = The for loop should run from i = 0 to i < n, not i <= n [OK]
- Using i <= n instead of i < n in loop
- Starting slow pointer incorrectly
- Returning wrong node after removal
Solution
Step 1: Identify the 5th node from the end
Since the list has 5 nodes, the 5th from the end is the first node with value 10.Step 2: Remove the first node and update head
Removing node 10 means the new head is node 20, so list becomes 20 -> 30 -> 40 -> 50 -> null.Final Answer:
20 -> 30 -> 40 -> 50 -> null -> Option CQuick Check:
Remove first node = 20 -> 30 -> 40 -> 50 -> null [OK]
- Not updating head when first node is removed
- Removing wrong node counting from end
- Confusing list length with N
Ready to prove it?
Pass the test and this pattern moves unknown
