Learn/DSA Patterns
DSA PatternsLinked Listseasy8 min read

Find Middle of Linked List

Move fast two steps and slow one step — when fast reaches the end, slow is at the middle. This single trick finds the midpoint in one pass with no length calculation, and is the essential first step in palindrome checking, merge sort on lists, and reordering problems.

#fast-slow#linked-list#middle#two-pointers#beginner#interview
Table of contents

Before we start

This is the simplest fast/slow pointer application. It deserves its own chapter because it is the building block for three harder patterns: palindrome linked list, merge sort on a linked list, and the reorder-list problem (Chapter 4.7). Once you understand exactly which node slow lands on — and why there are two valid "middles" for even-length lists — you will never get the off-by-one wrong again.


Picture this first (no code yet)

A real-life story

Two people start at the beginning of a queue. The first person (slow) shuffles forward one step at a time. The second person (fast) strides forward two steps at a time. When the fast person reaches the end of the queue and can't take another full double-step, the slow person is standing exactly at the middle of the queue.

No counting. No measuring the full length first. The ratio of speeds — 2:1 — guarantees that slow covers exactly half the distance fast covers.


The actual problem

Middle of the Linked List (LC #876):

Given the head of a linked list, return the middle node. If there are two middle nodes (even length), return the second middle node.

12345return node 3   (length 5, one middle)
1234return node 3   (length 4, second of two middles)

Without fast/slow: traverse once to count length (say n), traverse again to position n//2. Two passes, O(n) time, O(1) space.

With fast/slow: one pass, O(n) time, O(1) space.


The turning point

Pause & think

Slow moves 1 step per iteration, fast moves 2. When fast finishes, slow has moved half as many steps. For a list of 5 nodes (positions 1–5), how many steps does fast take to reach the end? How many steps does slow take? Which node is slow on?

Try it with 4 nodes too. Do you get node 3 in both cases?

Walk through both cases

5 nodes (1→2→3→4→5):

Start: slow=1, fast=1
Step 1: slow=2, fast=3
Step 2: slow=3, fast=5
Next: fast.next is None → stop.
Slow is at node 3 ✅ (middle of 5)

4 nodes (1→2→3→4):

Start: slow=1, fast=1
Step 1: slow=2, fast=3
Step 2: slow=3, fast=None (fast=3.next.next=4.next=None)

Wait — let me re-check. fast=3, fast.next=4, fast.next.next=None.
While condition: fast and fast.next → fast=3 (truthy), fast.next=4 (truthy) → enter loop.
slow=3, fast=None.
Now while: fast=None → exit.
Slow is at node 3 ✅ (second of two middles for length 4)

The one idea to remember

The entire pattern in one sentence

While fast and fast.next are both non-null, advance slow one step and fast two steps — when the loop exits, slow is at the middle node (or the second middle for even-length lists).


The code, line by line

def middleNode(head):
    slow = fast = head

    while fast and fast.next:       # fast needs 2 steps each iteration
        slow = slow.next
        fast = fast.next.next

    return slow                     # slow is at middle

Three lines of logic. Read against the story:

  • while fast and fast.next: — continue while fast can take a full two-step. fast checks the current node is not None (so fast.next is safe to access). fast.next checks the next node is not None (so fast.next.next is safe to access).
  • fast = fast.next.next — two steps in one assignment.
  • return slow — slow has moved exactly half the steps fast moved.

Watch it happen, frame by frame

Odd length: 1 → 2 → 3 → 4 → 5

     slow  fast
  ①  [1]   [1][2]   [3]     (after step 1)
  ③  [3]   [5]     (after step 2)

fast.next = None → while exits.
Return slow = node 3

Even length: 1 → 2 → 3 → 4

     slow  fast
  ①  [1]   [1][2]   [3]     (after step 1)
  ③  [3]   none    (fast=3.next.next=None)

fast = None → while exits.
Return slow = node 3  ✅  (second middle)

Length 2: 1 → 2

slow=1, fast=1
While: fast=1 (ok), fast.next=2 (ok) → enter.
slow=2, fast=None.
While: fast=None → exit.
Return slow = node 2  ✅  (second middle of length-2 list)

Length 1: 1

slow=1, fast=1
While: fast=1 (ok), fast.next=None → exit immediately.
Return slow = node 1

The first vs second middle question

Some problems want the first middle (for even-length lists). The standard code above gives the second middle (LC #876 asks for second). To get the first middle, move fast one step ahead at the start:

# Returns FIRST middle for even-length (second for odd — same result)
slow, fast = head, head.next     # fast starts one ahead
while fast and fast.next:
    slow = slow.next
    fast = fast.next.next
return slow

Which to use? Read the problem. For Palindrome Linked List (Chapter 4.7), you need the first middle so you can reverse the second half cleanly. For LC #876, you return the second middle. Know both and choose deliberately.


Application: Palindrome Linked List (LC #234)

The full algorithm:

  1. Find the middle (first middle for even-length).
  2. Reverse the second half (Chapter 4.3).
  3. Compare node-by-node with the first half.
  4. (Optional) Restore the list.
def isPalindrome(head):
    # Step 1: find first middle
    slow, fast = head, head.next
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next

    # Step 2: reverse second half
    prev, curr = None, slow.next
    while curr:
        nxt  = curr.next
        curr.next = prev
        prev = curr
        curr = nxt
    # prev is now the head of the reversed second half

    # Step 3: compare
    left, right = head, prev
    while right:               # right half may be shorter for odd length
        if left.val != right.val:
            return False
        left  = left.next
        right = right.next
    return True

This whole algorithm is O(n) time, O(1) space — no extra array.


Where to spot this pattern

Trigger words:

  • "find the middle of a linked list"
  • "split the list in half" (merge sort on lists)
  • "palindrome linked list" — always starts with finding the middle
  • "reorder list" — split, reverse second half, merge (Chapter 4.7)

Common traps

Watch out for these

  • Using while fast.next and fast.next.next: instead of while fast and fast.next:. Both work for non-empty lists, but the latter is more robust — it handles length-1 lists where fast.next is already None on the first check.
  • Confusing first and second middle. Standard code (slow = fast = head) gives the second middle for even-length. Shifting fast forward by one (fast = head.next) gives the first middle. Know which your specific problem needs.
  • Not disconnecting the first half from the second before reversing. In Palindrome Linked List, slow.next = None before reversing the second half prevents infinite loops during comparison. Some implementations skip this — it usually still works, but it's cleaner to cut the list at the midpoint.

Remember this forever

Find Middle — one loop

slow = fast = head
while fast and fast.next:
    slow = slow.next
    fast = fast.next.next
# slow is at SECOND middle (or only middle for odd length)

For FIRST middle: start fast = head.next.

Used in: Palindrome LL → find middle → reverse second half → compare.

Trap: while fast AND fast.next — both conditions needed.


Check yourself

For a list of length 6, which node does `slow` land on with the standard code? Which with the shifted-fast variant?

Standard (slow=fast=head):

Start: slow=1, fast=1
Step 1: slow=2, fast=3
Step 2: slow=3, fast=5
Step 3: slow=4, fast=None (fast=5.next.next=None)
Return node 4 — the SECOND middle (positions 3 and 4 are the two middles; second = node 4)

Shifted (fast=head.next):

Start: slow=1, fast=2
Step 1: slow=2, fast=4
Step 2: slow=3, fast=None (fast=4.next.next=None)
Return node 3 — the FIRST middle
Why is the `while fast and fast.next` condition necessary to have both parts? What specific case does each guard against?

fast guards against the case where the list has an odd number of nodes and fast lands exactly on the last node after the previous step — fast.next would be None, and attempting fast.next.next on a None reference would crash. fast.next guards against fast reaching the second-to-last node for even-length lists — after fast = fast.next.next, fast would become None, which is correct, but fast.next.next without the fast.next check would try None.next and crash. Together, they ensure both steps are safe before executing them.


Practice problems

ProblemDifficultyWhat to noticeLink
Middle of the Linked ListEasySecond middle for even; while fast and fast.nextLC #876
Palindrome Linked ListEasyMiddle → reverse second half → compareLC #234
Reorder ListMediumMiddle → reverse second half → merge alternatelyLC #143
Sort List (Merge Sort)MediumFind middle, recursively sort both halves, mergeLC #148

Next up: Reverse a Linked List — the most fundamental linked list operation: three pointers, one pass, O(1) space, and the basis for every "reverse a portion" problem.