LeetCode #2095 Medium

Delete the Middle Node of a Linked List

Delete the Middle Node of a Linked List: remove the node at index ⌊n/2⌋ (0-indexed) and return the modified head.

Constraints
  • The number of nodes is in the range [1, 10⁵].
  • 1 <= Node.val <= 10⁵
linked-listtwo-pointers
Open on LeetCode ↗
02

Intuition

You cannot index into a linked list, and counting first means two passes. Instead run a fast pointer at double speed: when it reaches the end, the slow pointer sits at the middle. Keep one node behind slow so the deletion is a single pointer rewrite.

How to spot this pattern

Fast and slow pointers are the standard answer to any 'find a position defined by a fraction of the length' question on a linked list — middle, cycle start, n-th from the end. The tell is needing a positional target without a known length. The extra prev pointer is the deletion-specific addition.

03

Approach

Try it first

Before reading on: if one pointer moves twice as fast as another, where is the slow one when the fast one finishes? Then work out what else you must hold on to in order to actually unlink a node. Aim for one pass, O(1) space.

1

Finding the middle without knowing the length

Advance slow one node and fast two nodes per iteration. Because fast covers twice the ground, when it runs off the end slow has covered exactly half — landing on index ⌊n/2⌋, which is precisely the node to delete. This is the tortoise-and-hare traversal, and it finds the middle in a single pass without ever computing the length.

2

Why you must track the previous node

Deleting from a singly linked list means making the predecessor skip over the target: prev.next = slow.next. Since you cannot walk backwards, prev has to be maintained as you go — one node behind slow at all times. Without it you would have the middle node in hand but no way to detach it, which is the most common stumbling block on this problem.

3

The loop condition and the single-node case

Use while fast and fast.next so fast.next.next is never dereferenced on a null. For a list of one node the middle is the head itself and the answer is an empty list, so return None immediately — the general loop cannot express that, because there is no predecessor to rewrite. Everything else is handled uniformly: O(n) time, O(1) space, one pass.

04

Solution & live demo

1class Solution:
2 def deleteMiddle(self, head):
3 if not head.next:
4 return None
5 slow, fast = head, head
6 prev = None
7 while fast and fast.next:
8 prev = slow
9 slow = slow.next
10 fast = fast.next.next
11 prev.next = slow.next
12 return head
05

Common pitfalls

Not keeping the previous node

✗ Wrong
while fast and fast.next:
    slow = slow.next
    fast = fast.next.next
# slow is the middle, but now what?
✓ Right
prev = slow
slow = slow.next

A singly linked list cannot be walked backwards, so without prev there is no way to bypass the middle node. You end up holding the right node with no means to remove it.

Wrong loop guard

✗ Wrong
while fast.next and fast.next.next:
✓ Right
while fast and fast.next:

The two forms stop at different places, so slow lands one node early on even-length lists — deleting index n/2 − 1 instead of n/2. The guard must match the definition of the middle you want.

Forgetting the single-node case

✗ Wrong
slow, fast = head, head
# straight into the loop
✓ Right
if not head.next:
    return None

With one node the loop body never runs, so prev stays None and prev.next raises an AttributeError. Deleting the only node must return an empty list.

06

Edge cases

Single node, e.g. [1]

The middle is the head; return null since deleting it empties the list.

Two nodes, e.g. [1,2]

⌊2/2⌋ = 1, so the second node is removed, leaving [1].

Odd length, e.g. [1,2,3,4,5]

Fast stops on the last node and slow sits at index 2, the true centre.

Even length, e.g. [1,2,3,4]

Fast runs off the end and slow lands on index 2, the later of the two middles — which is what ⌊n/2⌋ specifies.

Deleting the last node

Only possible for n ≤ 2; prev.next becomes null and the list ends cleanly.

07

Complexity

Time
O(n)
Space
O(1)
One pass; the fast pointer travels the list once while slow covers half.