Remove Nth Node from End of List in DSA Go - 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.
Specifically, how many steps does the program take when the list gets bigger?
Analyze the time complexity of the following code snippet.
func removeNthFromEnd(head *ListNode, n int) *ListNode {
dummy := &ListNode{Next: head}
first, second := dummy, dummy
for i := 0; i <= n; i++ {
first = first.Next
}
for first != nil {
first = first.Next
second = second.Next
}
second.Next = second.Next.Next
return dummy.Next
}
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: Two loops that move pointers through the list.
- How many times: The first loop runs n+1 times; the second loop runs (length of list - n - 1) times.
As the list gets longer, the total steps grow roughly in a straight line with the list size.
| 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 list size.
[X] Wrong: "Because we only move pointers a few times, the time is constant O(1)."
[OK] Correct: The loops move through the list nodes, so the number of steps depends on the list length, not fixed.
Understanding this linear time complexity helps you explain why two-pointer techniques are efficient for linked lists and shows your grasp of pointer traversal.
"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 requires removing the node that is Nth from the end, not from the start or adding nodes.Step 2: Clarify the operation on the linked list
We must delete the node counting from the end, which is different from reversing or finding a value.Final Answer:
Remove the node that is the Nth from the end of the list -> Option CQuick Check:
Remove Nth from end = Remove Nth node from end [OK]
- Confusing Nth from end with Nth from start
- Thinking the problem asks to add nodes
- Assuming the list should be reversed
Solution
Step 1: Identify Go struct syntax
In Go, structs use 'type Name struct { fields }' and pointers use '*Type'.Step 2: Match correct field names and types
type ListNode struct { Val int; Next *ListNode } uses 'Val int' and 'Next *ListNode' which is the standard for singly linked list nodes in Go.Final Answer:
type ListNode struct { Val int; Next *ListNode } -> Option AQuick Check:
Go struct with pointer field = type ListNode struct { Val int; Next *ListNode } [OK]
- Using C/C++ or Java syntax in Go code
- Missing pointer '*' for Next field
- Incorrect field names or 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
Node 3's next should point to node 5, skipping node 4.Final Answer:
1 -> 2 -> 3 -> 5 -> null -> Option BQuick Check:
Remove 2nd from end (4) = 1->2->3->5 [OK]
- Removing the wrong node counting from start
- Breaking links incorrectly causing list corruption
- Off-by-one errors in counting nodes
func removeNthFromEnd(head *ListNode, n int) *ListNode {
dummy := &ListNode{0, head}
first, second := dummy, dummy
for i := 0; i < n; i++ {
first = first.Next
}
for first.Next != nil {
first = first.Next
second = second.Next
}
second.Next = second.Next.Next
return head
}Solution
Step 1: Understand dummy node usage
Dummy node helps handle edge cases like removing the first node. The result list starts at dummy.Next.Step 2: Check return statement
Returning 'head' ignores changes if first node was removed. Should return dummy.Next instead.Final Answer:
Returns head instead of dummy.Next, so removal of first node fails -> Option DQuick Check:
Return dummy.Next to handle first node removal [OK]
- Returning original head ignoring dummy node
- Not using dummy node for edge cases
- Incorrect loop bounds causing panic
Solution
Step 1: Identify the 5th node from the end
The list length is 5, so the 5th from end is the first node with value 10.Step 2: Remove the first node and link dummy to second node
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 AQuick Check:
Remove 5th from end (first node) = 20->30->40->50 [OK]
- Removing wrong node when N equals list length
- Not updating head pointer after removal
- Confusing node positions counting from start vs end
Ready to prove it?
Pass the test and this pattern moves unknown
