Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

Remove Nth Node
DSA

Remove Nth Node

Learn how to remove a node at a specific position using an efficient two-pointer technique.

Deletion is rewiring: find the node BEFORE the target → prev.next = prev.next.next.

Focus on recognizing:

“Remove kth node” / “one pass required” → gap trick between two pointers


Pattern 1: Remove N-th From End (One Pass)

Removing the 2nd-from-end of [1,2,3,4,5] — the fixed gap parks slow exactly before node 3. Press to animate.

Remove Nth Node From End

Delete the n-th node from the end of a list — compare a one-pass two-pointer gap trick with a two-pass length-then-walk approach.

Advance fast n+1 nodes ahead (using a dummy head so the head itself can be deleted), then walk both until fast is null; slow sits just before the target, which you then bypass.

LINKED LIST VISUALIZER
Steps
12345
Press ▶ to animate, or step through manually.
Variables
keys: ← → space F
Pseudocode

                        1
                        dummy → head; fast = slow = dummy
                      
                        2
                        for i in 0..n:            // gap of n+1
                      
                        3
                          fast = fast.next
                      
                        4
                        while fast:               // walk together
                      
                        5
                          fast = fast.next; slow = slow.next
                      
                        6
                        slow.next = slow.next.next  // remove
                      

Fast gets an n-step head start; when it hits the end, slow stands right before the victim:

public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(0, head);
    ListNode fast = dummy, slow = dummy;

    for (int i = 0; i <= n; i++)   // n + 1 steps of gap
        fast = fast.next;

    while (fast != null) {
        fast = fast.next;
        slow = slow.next;
    }

    slow.next = slow.next.next;    // remove target

    return dummy.next;
}
def remove_nth_from_end(head, n):
    dummy = ListNode(0, head)
    fast = slow = dummy

    for _ in range(n + 1):     # n + 1 steps of gap
        fast = fast.next

    while fast:
        fast = fast.next
        slow = slow.next

    slow.next = slow.next.next # remove target

    return dummy.next
ListNode* removeNthFromEnd(ListNode* head, int n) {
    ListNode dummy(0, head);
    ListNode *fast = &dummy, *slow = &dummy;

    for (int i = 0; i <= n; i++)  // n + 1 steps of gap
        fast = fast->next;

    while (fast) {
        fast = fast->next;
        slow = slow->next;
    }

    slow->next = slow->next->next; // remove target

    return dummy.next;
}
function removeNthFromEnd(head, n) {
  const dummy = new ListNode(0, head);
  let fast = dummy,
    slow = dummy;

  for (let i = 0; i <= n; i++) fast = fast.next; // gap n+1

  while (fast) {
    fast = fast.next;
    slow = slow.next;
  }

  slow.next = slow.next.next; // remove target

  return dummy.next;
}

The dummy node makes “remove the head” a no-special-case operation.


Pattern 2: Remove N-th From Start

Walk n−1 steps and relink. Watch the head-removal edge case. Press to animate.

Remove N-th Node From The Start

Remove the n-th node (1-indexed) from the head of a linked list.

Walk n-1 steps to land on the target, then unlink it by wiring prev.next past it. If prev is null the head is being removed, so return head.next.

LINKED LIST VISUALIZER
Steps
48151623
Press ▶ to animate, or step through manually.
Variables
keys: ← → space F
Pseudocode

                        1
                        prev = null; cur = head
                      
                        2
                        for i in 1..n-1: cur = cur.next
                      
                        3
                        if prev == null: return head.next   // removing head
                      
                        4
                        prev.next = cur.next
                      

Same rewiring, direct index walk:

public ListNode removeNth(ListNode head, int n) {   // 1-indexed
    if (n == 1) return head.next;

    ListNode cur = head;
    for (int i = 1; i < n - 1; i++)
        cur = cur.next;              // stop BEFORE target

    cur.next = cur.next.next;
    return head;
}
def remove_nth(head, n):         # 1-indexed
    if n == 1:
        return head.next

    cur = head
    for _ in range(n - 2):
        cur = cur.next           # stop BEFORE target

    cur.next = cur.next.next
    return head
ListNode* removeNth(ListNode* head, int n) {  // 1-indexed
    if (n == 1) return head->next;

    ListNode* cur = head;
    for (int i = 1; i < n - 1; i++)
        cur = cur->next;             // stop BEFORE target

    cur->next = cur->next->next;
    return head;
}
function removeNth(head, n) {
  // 1-indexed
  if (n === 1) return head.next;

  let cur = head;
  for (let i = 1; i < n - 1; i++) cur = cur.next; // before target

  cur.next = cur.next.next;
  return head;
}

Pattern 3: Delete Given Node (No Head Access)

Steal the neighbour’s value, skip past it — identity swap trick. Press to animate.

Delete Node In A Linked List

Delete a node from a singly linked list given only a pointer to that node (no head).

Since the previous node is unreachable, copy the successor's value into the target and then bypass the successor. Result looks identical value-wise. It cannot work when the target is the tail.

LINKED LIST VISUALIZER
Steps
419
Press ▶ to animate, or step through manually.
Variables
keys: ← → space F
Pseudocode

                        1
                        // target = the 1, head unknown
                      
                        2
                        node.val = node.next.val
                      
                        3
                        node.next = node.next.next
                      

Copy the NEXT node’s value into this one, then skip it:

public void deleteNode(ListNode node) {
    node.val = node.next.val;
    node.next = node.next.next;
}
def delete_node(node):
    node.val = node.next.val
    node.next = node.next.next
void deleteNode(ListNode* node) {
    node->val = node->next->val;
    node->next = node->next->next;
}
function deleteNode(node) {
  node.val = node.next.val;
  node.next = node.next.next;
}

Works because the target is never the tail — guaranteed by these problems.


Common Mistakes

Stopping ON the target instead of before it.

You can’t delete a node without access to its predecessor (except the value-copy trick).


Counting length first.

Two passes work but interviews ask for one — the gap trick is the expected answer.


Losing the head reference.

Return dummy.next, not head — head may have been the removed node.


Complexity

OperationTimeSpace
From end (gap trick)O(n)O(1)
From startO(n)O(1)
Given nodeO(1)O(1)

My Private Notes

Notes are auto-saved locally to this device.