0
0
DSA Pythonprogramming

Remove Nth Node from End of List in DSA Python

Choose your learning style9 modes available
Mental Model
To remove the nth node from the end, we find the node just before it by moving two pointers with a gap of n between them.
Analogy: Imagine two friends walking on a path where one starts n steps ahead. When the front friend reaches the end, the other is right before the target friend to be removed.
head -> 1 -> 2 -> 3 -> 4 -> 5 -> null
          ↑
        slow
                 ↑
               fast
Dry Run Walkthrough
Input: list: 1 -> 2 -> 3 -> 4 -> 5, remove 2nd node from end
Goal: Remove the 2nd node from the end, which is node with value 4
Step 1: Move fast pointer n=2 steps ahead
head -> 1 -> 2 -> 3 -> 4 -> 5 -> null
slow at dummy, fast at 2
Why: To create a gap of n nodes between slow and fast pointers
Step 2: Move slow and fast pointers forward together until fast reaches the end
head -> 1 -> 2 -> 3 -> 4 -> 5 -> null
slow at 3, fast at 5
Why: Slow pointer will be just before the node to remove
Step 3: Remove node after slow (node 4) by changing slow.next to slow.next.next
head -> 1 -> 2 -> 3 -> 5 -> null
Why: This skips the 4th node, effectively removing it
Result:
1 -> 2 -> 3 -> 5 -> null
Annotated Code
DSA Python
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def remove_nth_from_end(head: ListNode, n: int) -> ListNode:
    dummy = ListNode(0, head)  # dummy node to handle edge cases
    slow = dummy
    fast = dummy

    # Move fast pointer n steps ahead
    for _ in range(n):
        fast = fast.next

    # Move both pointers until fast reaches the end
    while fast.next:
        slow = slow.next
        fast = fast.next

    # Remove the nth node from end
    slow.next = slow.next.next

    return dummy.next

def print_list(head: ListNode):
    curr = head
    result = []
    while curr:
        result.append(str(curr.val))
        curr = curr.next
    print(" -> ".join(result) + " -> null")

# Driver code
head = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))
n = 2
new_head = remove_nth_from_end(head, n)
print_list(new_head)
dummy = ListNode(0, head) # dummy node to handle edge cases
Create dummy node to simplify removal especially if head is removed
for _ in range(n): fast = fast.next
Advance fast pointer n steps ahead to create gap
while fast.next: slow = slow.next fast = fast.next
Move slow and fast together until fast reaches last node
slow.next = slow.next.next
Skip the target node by linking slow.next to node after next
return dummy.next
Return head of modified list, skipping dummy
OutputSuccess
1 -> 2 -> 3 -> 5 -> null
Complexity Analysis
Time: O(n) because we traverse the list twice with two pointers but each node is visited at most once
Space: O(1) because we only use a few pointers and no extra data structures
vs Alternative: Naive approach would find list length first then remove node, requiring two passes; this uses one pass with two pointers for efficiency
Edge Cases
Removing the head node (n equals list length)
Dummy node allows removal without special case; head is removed correctly
DSA Python
dummy = ListNode(0, head)  # dummy node to handle edge cases
List with only one node and n=1
Returns empty list (null) after removal
DSA Python
dummy = ListNode(0, head)  # dummy node to handle edge cases
n is 1 (remove last node)
Last node is removed by slow pointer stopping at second last node
DSA Python
while fast.next:
    slow = slow.next
    fast = fast.next
When to Use This Pattern
When asked to remove the nth node from the end of a linked list, use two pointers spaced n apart to find the target node in one pass.
Common Mistakes
Mistake: Not using a dummy node and failing when removing the head node
Fix: Add a dummy node before head to simplify removal logic
Mistake: Moving fast pointer n+1 steps instead of n, causing off-by-one errors
Fix: Move fast pointer exactly n steps ahead before moving both pointers
Summary
Removes the nth node from the end of a singly linked list in one pass.
Use when you need efficient removal without counting total nodes first.
The key is to keep two pointers n nodes apart so the slow pointer reaches just before the target node.