Bird
0
0
DSA Cprogramming

Remove Nth Node from End of List in DSA C

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 fixed gap.
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 spot to remove.
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 2 steps ahead
head -> 1 -> 2 -> 3 -> 4 -> 5 -> null
          slow ↑         fast ↑
Why: Create a gap of n=2 between slow and fast pointers
Step 2: Move both slow and fast pointers one step until fast reaches the end
head -> 1 -> 2 -> 3 -> 4 -> 5 -> null
               slow ↑               fast ↑
Why: Keep the gap so slow points to node before target
Step 3: Move both pointers one more step
head -> 1 -> 2 -> 3 -> 4 -> 5 -> null
                    slow ↑                    fast ↑
Why: Slow is now just before the node to remove
Step 4: Remove node after slow by linking slow to slow->next->next
head -> 1 -> 2 -> 3 -> 5 -> null
Why: Skip the 4th node to remove it
Result:
head -> 1 -> 2 -> 3 -> 5 -> null
Annotated Code
DSA C
#include <stdio.h>
#include <stdlib.h>

// Define node structure
typedef struct Node {
    int val;
    struct Node* next;
} Node;

// Helper to create new node
Node* newNode(int val) {
    Node* node = (Node*)malloc(sizeof(Node));
    node->val = val;
    node->next = NULL;
    return node;
}

// Function to remove nth node from end
Node* removeNthFromEnd(Node* head, int n) {
    Node dummy;
    dummy.next = head;
    Node* slow = &dummy;
    Node* fast = &dummy;

    // Move fast n steps ahead
    for (int i = 0; i < n; i++) {
        fast = fast->next; // advance fast pointer
    }

    // Move both pointers until fast reaches the last node
    while (fast->next != NULL) {
        slow = slow->next; // advance slow pointer
        fast = fast->next; // advance fast pointer
    }

    // Remove the nth node from end
    Node* toDelete = slow->next;
    slow->next = slow->next->next; // bypass the node
    free(toDelete); // free memory

    return dummy.next;
}

// Helper to print list
void printList(Node* head) {
    Node* curr = head;
    while (curr != NULL) {
        printf("%d", curr->val);
        if (curr->next != NULL) printf(" -> ");
        curr = curr->next;
    }
    printf(" -> null\n");
}

int main() {
    // Create list 1->2->3->4->5
    Node* head = newNode(1);
    head->next = newNode(2);
    head->next->next = newNode(3);
    head->next->next->next = newNode(4);
    head->next->next->next->next = newNode(5);

    printf("Original list: ");
    printList(head);

    int n = 2;
    head = removeNthFromEnd(head, n);

    printf("After removing %dth node from end: ", n);
    printList(head);

    return 0;
}
for (int i = 0; i < n; i++) { fast = fast->next; // advance fast pointer }
advance fast pointer n steps to create gap
while (fast->next != NULL) { slow = slow->next; // advance slow pointer fast = fast->next; // advance fast pointer }
move both pointers until fast reaches end
slow->next = slow->next->next; // bypass the node
remove nth node by skipping it
OutputSuccess
Original list: 1 -> 2 -> 3 -> 4 -> 5 -> null After removing 2th node from end: 1 -> 2 -> 3 -> 5 -> null
Complexity Analysis
Time: O(n) because we traverse the list once with two pointers
Space: O(1) because we use only a few pointers, no extra list
vs Alternative: Compared to counting length first then removing, this uses one pass instead of two, saving time
Edge Cases
Removing the head node (n equals list length)
Dummy node helps remove head easily without special code
DSA C
Node dummy; dummy.next = head;
List with only one node and n=1
Returns empty list (null) after removal
DSA C
slow->next = slow->next->next;
n is 1 (remove last node)
Slow pointer stops at second last node and removes last node
DSA C
while (fast->next != NULL)
When to Use This Pattern
When asked to remove a node from the end of a linked list in one pass, use two pointers spaced n apart to find the target efficiently.
Common Mistakes
Mistake: Not using a dummy node and failing when removing the head node
Fix: Use a dummy node pointing to head to simplify edge cases
Mistake: Moving fast pointer n+1 steps instead of n, causing null pointer errors
Fix: Move fast pointer exactly n steps ahead before moving both pointers
Mistake: Not freeing the removed node's memory
Fix: Call free() on the removed node to avoid memory leaks
Summary
Removes the nth node from the end of a singly linked list in one pass.
Use when you need efficient removal from the end without counting list length first.
Keep two pointers n nodes apart so when the front reaches the end, the back is just before the target.