Skip to content

Remove Nth Node From End of List

Given the head of a linked list, remove the nth node from the end of the list and return the head of the modified list.

You must solve this in one pass when possible, but a two-pass solution is a good warm-up.

InputnOutputExplanation
1 → 2 → 3 → 4 → 521 → 2 → 3 → 5The 4th node (value 4) is removed.
11(empty)Single node is removed; result is empty.
1 → 211Remove the 2nd node (end); result is [1].
1 → 222Remove the 1st node (head); result is [2].
  • The number of nodes in the list is sz.
  • 1 <= sz <= 30
  • 0 < n <= sz
  • All node values are unique.
ApproachTimeSpacePassesBest When
Two PassO(L)O(1)2Learning the basic algorithm or when clarity is prioritized
Two Pointers (One Pass)O(L)O(1)1Interview setting or when single-pass constraint is required
  • Pick Two Pass if you are learning linked list concepts for the first time.
  • Pick Two Pointers if you want the optimal solution or are in an interview where “one pass” is mentioned.
Single Pass (Optimal)
Two Pointers
O(L) time · O(1) space
Easier to Understand
Two Pass
O(L) time · O(1) space
✓ Simple

Count the total number of nodes in the first pass, then find and skip the target node in the second pass.

This approach is straightforward: first measure the list, then navigate to the node before the one to remove.

⏱ Time O(L) Two passes 💾 Space O(1)

Input: 1 → 2 → 3 → 4 → 5, n = 2

Pass 1 (Count): Length = 5

Pass 2 (Remove): We want to skip the node at position 5 - 2 = 3 from the start (0-indexed: position 3).

  • Navigate to position 2 (the node with value 3).
  • Set node.next = node.next.next (skip the 4).
  • Result: 1 → 2 → 3 → 5

Another case: n = 1 (remove the last node)

Pass 1 (Count): Length = 5

Pass 2 (Remove): We want to skip the node at position 5 - 1 = 4 from the start.

  • Navigate to position 3 (the node with value 4).
  • Set node.next = node.next.next (skip the 5).
  • Result: 1 → 2 → 3 → 4

Edge case: 1, n = 1 (remove the only node)

Pass 1 (Count): Length = 1

Since length == n, return head.next, which is null.

  • Result: (empty list)
function removeNthNodeTwoPass(head, n):
// First pass: count total nodes
length = 0
current = head
while current != null:
length++
current = current.next
// Edge case: removing the head
if length == n:
return head.next
// Second pass: find the node before the one to remove
current = head
for i from 0 to length - n - 2:
current = current.next
// Remove the nth node
current.next = current.next.next
return head
remove_nth_node_from_end_of_list_two_pass.py
from typing import Optional
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def remove_nth_node_two_pass(head: Optional[ListNode], n: int) -> Optional[ListNode]:
"""
Remove the nth node from the end of a linked list using two passes.
Approach:
1. First pass: count the total number of nodes
2. Second pass: find and skip the nth node from the end
Time: O(L) + O(L-n) = O(L)
Space: O(1)
"""
# First pass: count the total nodes
length = 0
current = head
while current:
length += 1
current = current.next
# Edge case: removing the head node
if length == n:
return head.next
# Second pass: find the node before the one to remove
current = head
for i in range(length - n - 1):
current = current.next
# Remove the nth node
current.next = current.next.next
return head
# Helper function to create a linked list from a list
def create_linked_list(values):
if not values:
return None
head = ListNode(values[0])
current = head
for val in values[1:]:
current.next = ListNode(val)
current = current.next
return head
# Helper function to convert linked list to list for easy printing
def linked_list_to_list(head):
result = []
current = head
while current:
result.append(current.val)
current = current.next
return result
# Test cases
if __name__ == "__main__":
# Test 1: [1, 2, 3, 4, 5], n=2
head1 = create_linked_list([1, 2, 3, 4, 5])
result1 = remove_nth_node_two_pass(head1, 2)
print(linked_list_to_list(result1)) # [1, 2, 3, 5]
# Test 2: [1], n=1
head2 = create_linked_list([1])
result2 = remove_nth_node_two_pass(head2, 1)
print(linked_list_to_list(result2)) # []
# Test 3: [1, 2], n=2
head3 = create_linked_list([1, 2])
result3 = remove_nth_node_two_pass(head3, 2)
print(linked_list_to_list(result3)) # [2]
# Test 4: [1, 2], n=1
head4 = create_linked_list([1, 2])
result4 = remove_nth_node_two_pass(head4, 1)
print(linked_list_to_list(result4)) # [1]
Section titled “Approach 2: Two Pointers (One Pass - Recommended)”
★ Recommended

Use a dummy node and two pointers (fast and slow) with a controlled gap. Move both pointers in lockstep; when the fast pointer reaches the end, the slow pointer will be at the node before the one to remove.

The dummy node is the key: it cleanly handles the edge case of removing the head without special branching.

⏱ Time O(L) Single pass 💾 Space O(1)

Input: 1 → 2 → 3 → 4 → 5, n = 2

Setup: Create dummy: 0 → 1 → 2 → 3 → 4 → 5

  • Slow = dummy, fast = dummy

Move fast pointer n+1 = 3 steps ahead:

  • Step 1: fast = 1
  • Step 2: fast = 2
  • Step 3: fast = 3

Now there is a gap of 2 nodes between slow (dummy) and fast (3).

Move both pointers until fast reaches the end:

  • Move 1: slow = 1, fast = 4
  • Move 2: slow = 2, fast = 5
  • Move 3: slow = 3, fast = null

Fast is now null. Slow is at node 3.

Remove the next node: slow.next = slow.next.next

  • 3.next = 5 (skip 4)

Result: 0 → 1 → 2 → 3 → 5, return dummy.next = 1 → 2 → 3 → 5

Edge case: 1 → 2, n = 2 (remove the head)

Setup: Create dummy: 0 → 1 → 2

  • Slow = dummy, fast = dummy

Move fast pointer n+1 = 3 steps ahead:

  • Step 1: fast = 1
  • Step 2: fast = 2
  • Step 3: fast = null

Move both pointers until fast reaches the end:

  • fast is already null, so the loop does not run.

Remove the next node: slow.next = slow.next.next

  • dummy.next = 2 (skip 1)

Result: 0 → 2, return dummy.next = 2

function removeNthNodeTwoPointers(head, n):
dummy = new Node(0)
dummy.next = head
slow = dummy
fast = dummy
// Move fast pointer n+1 steps ahead
for i from 0 to n:
if fast == null:
return head
fast = fast.next
// Move both pointers until fast reaches the end
while fast != null:
slow = slow.next
fast = fast.next
// Remove the nth node
slow.next = slow.next.next
return dummy.next
remove_nth_node_from_end_of_list_two_pointers.py
from typing import Optional
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def remove_nth_node_two_pointers(head: Optional[ListNode], n: int) -> Optional[ListNode]:
"""
Remove the nth node from the end of a linked list using two pointers in one pass.
Approach:
1. Create a dummy node pointing to head (handles edge case of removing head)
2. Use fast and slow pointers with a gap of n nodes between them
3. Move both pointers until fast reaches the end
4. Skip the target node by adjusting the slow pointer
Time: O(L) single pass
Space: O(1)
"""
# Create a dummy node to handle edge case of removing the head
dummy = ListNode(0)
dummy.next = head
slow = dummy
fast = dummy
# Move fast pointer n+1 steps ahead
for i in range(n + 1):
if not fast:
return head
fast = fast.next
# Move both pointers until fast reaches the end
while fast:
slow = slow.next
fast = fast.next
# Remove the nth node
slow.next = slow.next.next
return dummy.next
# Helper function to create a linked list from a list
def create_linked_list(values):
if not values:
return None
head = ListNode(values[0])
current = head
for val in values[1:]:
current.next = ListNode(val)
current = current.next
return head
# Helper function to convert linked list to list for easy printing
def linked_list_to_list(head):
result = []
current = head
while current:
result.append(current.val)
current = current.next
return result
# Test cases
if __name__ == "__main__":
# Test 1: [1, 2, 3, 4, 5], n=2
head1 = create_linked_list([1, 2, 3, 4, 5])
result1 = remove_nth_node_two_pointers(head1, 2)
print(linked_list_to_list(result1)) # [1, 2, 3, 5]
# Test 2: [1], n=1
head2 = create_linked_list([1])
result2 = remove_nth_node_two_pointers(head2, 1)
print(linked_list_to_list(result2)) # []
# Test 3: [1, 2], n=2
head3 = create_linked_list([1, 2])
result3 = remove_nth_node_two_pointers(head3, 2)
print(linked_list_to_list(result3)) # [2]
# Test 4: [1, 2], n=1
head4 = create_linked_list([1, 2])
result4 = remove_nth_node_two_pointers(head4, 1)
print(linked_list_to_list(result4)) # [1]

Animated walkthrough

Two-pointer gap maintains the distance to the target

Watch how the fast and slow pointers maintain a gap of exactly n nodes. When fast reaches the end, slow is perfectly positioned to remove the target node.

Step 1 of 4 Target: gap
Waiting to begin...
Array state
Memory / lookup state

✓ Simple

A third approach demonstrating an alternative technique for solving this problem. This implementation optimizes either time or space complexity compared to the previous approaches.

⏱ Time O(n) Optimized complexity 💾 Space O(1) Efficient space usage
function approach3():
// Implementation approach goes here
remove_nth_node_from_end_of_list_optimized.py
"""
Solution for Remove Nth Node From End of List
"""
def solve():
"""Implementation for approach 3 of Remove Nth Node From End of List"""
pass
if __name__ == "__main__":
print("Solution ready")