Algorithm

Middle of the Linked List

Two Pointer Pattern

Middle of the Linked List

Given the head of a singly linked list, return the middle node of the linked list. If there are two middle nodes, return the second middle node.

CONSTRAINTS
  • The number of nodes in the list is in the range [1, 100]
  • 1 <= Node.val <= 100
  • Solve in a single pass
EXAMPLE 1
Input: head = [1,2,3,4,5]
Output: [3,4,5]
Five nodes, so the single middle node is the third one. Returning a node in a linked list means returning it together with everything after it, hence [3,4,5].
EXAMPLE 2
Input: head = [1,2,3,4,5,6]
Output: [4,5,6]
Six nodes means there are two middle nodes, node 3 and node 4. The rule says return the second one, node 4, along with the rest of the list.
EXAMPLE 3
Input: head = [1]
Output: [1]
A single node is its own middle, so it is returned unchanged.
Do I return the middle node itself, or its value or index?
Return the node. Since this is a linked list, returning a node hands back that node plus everything chained after it — you cannot return it in isolation.
An even-length list has two middle nodes — which one do I return?
The second of the two. For [1,2,3,4,5,6] that is node 4, not node 3. Worth confirming with the interviewer, since a common variant asks for the first middle instead.
Can the list be empty?
No — the constraints guarantee at least one node, so you never have to return null. The smallest input is a single node, which is its own middle.

A singly linked list is a chain of nodes where each node only knows the address of the next node. We want the node sitting exactly in the middle. The annoying part: a linked list will not tell you how long it is, and you cannot jump to "position 5" the way you can with an array. The only move you are allowed is to start at the head and follow next, one node at a time. So how do you find the centre of something when you don't even know where its end is?

The obvious way: measure first, then walk halfway

Walk the whole list once and count the nodes. Now you know the length — say 6 — so the middle is node number 3. Go back to the head and walk 3 steps. Done.

python
length = 0
curr = head
while curr:                     # first walk: only to measure
    length += 1
    curr = curr.next

curr = head
for _ in range(length // 2):    # second walk: to the middle
    curr = curr.next
return curr

This is correct, and it is already reasonably fast — each walk touches N nodes, so it is O(N) time. But look at what it actually does: it walks the list once just to learn the length, throws that walk away, then walks the same nodes again. We pass over everything twice. Worth asking: was the length ever really the thing we needed, or only a means to find the halfway point?

Send a second pointer at double speed

Here is the move that removes the counting completely. Start two pointers at the head at the same time. One of them — call it slow — takes a single step each turn. The other — fast — takes two steps each turn. They leave together, but fast pulls ahead because it covers ground twice as quickly.

Now think about the distances, not the nodes. However many steps slow has taken, fast has taken exactly double. So at the very moment fast runs out of list — after covering the full length — slow has covered exactly half of it. And half the length is the middle. We never counted a thing; the speed difference did the measuring for us, in a single pass.

Writing it, and the one line that keeps it safe
python
slow = head
fast = head
while fast and fast.next:     # can fast still take two steps?
    slow = slow.next          # one step
    fast = fast.next.next     # two steps
return slow
Crucial Notethe loop checks both fast and fast.next before moving, and both halves matter. Because fast jumps two nodes, it needs two nodes ahead of it to be safe — if fast itself is null, or the node right after it is null, there is no room for a double step, so we stop. Checking only fast and then jumping two would run straight off the end and crash. This one guard is also exactly what makes both list shapes come out right:
- Odd length (say 5 nodes): fast lands on the last node, fast.next is null, the loop stops, and slow is on node 3 — the true middle.
- Even length (say 6 nodes): fast steps past the last node to null, the loop stops, and slow is on node 4 — the second of the two middle nodes, which is what the problem asked for.
Worked Example:head = [1, 2, 3, 4, 5]
- Start: slow on node 1, fast on node 1.
- Turn 1: slow moves to node 2, fast moves to node 3.
- Turn 2: slow moves to node 3, fast moves to node 5.
- Check: fast is on node 5 and fast.next is null — stop. slow is on node 3, the middle. Return it.

Three turns, one pass, and the answer just falls out.

The shape of this whole family — and how to spot it again

This is your first taste of same-direction two pointers, and it is worth seeing the general shape right now, because a whole run of problems is built on it. The idea: put two pointers at (or near) the front of one sequence and let them both move forward — but not locked together. The gap between them, or their difference in speed, is a fact you control on purpose, and that fact is what solves the problem. (This is the mirror image of the other big two-pointer style, where the pointers start at the two ends and move toward each other — you will meet that one a little later.)

Across the next few problems the "not locked together" part shows up in three concrete shapes, and recognising which shape a new problem wants is most of the work:
- Different speed — fast goes 2×. Exactly what we just did. Because one pointer outruns the other, you learn a positional fact: the middle here, and soon whether a linked list secretly loops back on itself (Linked List Cycle) and where that loop starts (Cycle II) — all without ever measuring the length.
- A fixed gap — fast starts N steps ahead, same speed. Hold the two pointers a constant N apart; the instant the front one reaches the end, the back one is exactly N from the end. That is how you reach the N-th node from the end in one pass (Remove Nth Node From End).
- Slow moves only when there is something worth keeping. The fast pointer reads every element; the slow pointer marks where to write the next element you want to keep, and it steps forward only when fast finds a keeper. This quietly rebuilds an array in place, with no second array — the engine behind Move Zeroes, Remove Duplicates, and Is Subsequence.

When should this pattern jump to mind? The strong signals: the input is a linked list and you're asked for the middle, a loop, or something counted "from the end"; or you're told to rearrange or filter an array in place, in O(1) extra space, keeping the order; or you simply cannot index into the structure or don't know its length up front. All three point at the same move — two pointers walking forward at a distance you control.

One honest limit to remember: the 2× speed trick depends on being able to take two steps safely, which is why the fast and fast.next guard is not optional. And same-direction pointers only work when a single forward sweep is enough to decide everything — if judging one element needs information from further ahead that you haven't seen yet, one forward pass won't cut it.

What it costs

One pass instead of two, and only two pointers of bookkeeping: O(N) time, O(1) space. It isn't asymptotically faster than count-then-walk — both are O(N) — but it does the job in a single sweep, and, more to the point, it is the very same move you'll reuse to detect cycles and reach end-relative nodes. Train the reflex: the moment you need a positional fact about a linked list and catch yourself wishing you could "just index into it," reach for a second pointer moving at a controlled speed or offset.

Interactive Strategy Visualization
TORTOISE & HARE ENGINE

Linear Discovery via 2-Pointer Speeds

1Slow (1x)Fast (2x)2345

Current Progress

Phase 1: Initialization

Both Slow and Fast pointers start at the head. In this race, the speeds are intentionally uneven to find the balance point.

Mathematical Core

If Pointer A moves @ speed 1 and Pointer B moves @ speed 2, when B hits the end ($L$), A will be at $L/2$. No counting nodes required!

Efficiency Strategy: One Pass Discovery

Traditional solutions use two passes (count then find). This method finds the middle in exactly one pass.

O(N) Time Two Passes
O(N) Time · O(1) Space Single Pass