1. Two-Pass Length Counting
Intuition
1. Traverse from head to null to count total length L.
2. Create a dummy node pointing to head.
3. The node to remove is at index L - n from dummy (0-indexed from dummy).
4. Advance a pointer L - n times from dummy, reaching the predecessor node.
5. Rewire curr.next = curr.next.next.
6. Return dummy.next.
When to apply: Intuitive baseline when two-pointer gap synchronization is unfamiliar.
Algorithm
- Find total node count L.
- Create dummy node pointing to head.
- Traverse (L - n) steps from dummy.
- Bypass target:
curr.next = curr.next.next. - Return
dummy.next.
#include <iostream> struct ListNode { int val; ListNode *next; ListNode() : val(0), next(nullptr) {} ListNode(int x) : val(x), next(nullptr) {} ListNode(int x, ListNode *next) : val(x), next(next) {}}; class Solution {public: ListNode* removeNthFromEnd(ListNode* head, int n) { int length = 0; ListNode* curr = head; while (curr != nullptr) { length++; curr = curr->next; } ListNode dummy(0, head); curr = &dummy; for (int i = 0; i < length - n; ++i) { curr = curr->next; } ListNode* toDelete = curr->next; curr->next = curr->next->next; delete toDelete; return dummy.next; }}; int main() { ListNode* head = new ListNode(1, new ListNode(2, new ListNode(3, new ListNode(4, new ListNode(5))))); Solution sol; ListNode* res = sol.removeNthFromEnd(head, 2); while (res != nullptr) { std::cout << res->val << " "; res = res->next; } std::cout << std::endl; return 0;}Time & Space Complexity
- Time complexity:
O(L)— Pass 1 takes L steps to count length. Pass 2 takes (L - n) steps to reach predecessor. Total operations = 2L - n = O(L). - Space complexity:
O(1)— Only requires integer counters and temporary pointers: O(1) auxiliary space.