Definition
- Fast-slow pointer – a technique where two pointers traverse at different speeds to find positional information.
- Slow pointer – advances one node per iteration.
- Fast pointer – advances two nodes per iteration.
- Termination – when fast reaches the end, slow is at the middle.
- Complexity – O(n) time, O(1) space, single pass without counting length.
At the National Bank of India, Rajesh stores a chain of transaction nodes and wants the middle transaction for a quick spot-check. He walks two fingers along the chain: one steps on every node, the other skips every other node. When the fast finger runs off the end, the slow finger is sitting right in the middle.
Understanding the Concepts
What is the problem?
Given the head of a singly linked list, return the middle node. If there are two middle nodes (even length), return the second one.
At the National Bank of India, the audit tool needs the middle transaction from a chain for a quick sampling check, without scanning the chain twice.
How does the fast-slow pointer technique work?
Start both pointers at the head. Advance slow by one and fast by two each iteration. When fast reaches the end, slow is at the middle.
package com.bank.service;
public class MiddleOfLinkedList {
public static ListNode findMiddle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
public static void main(String[] args) {
// Build: 100 -> 200 -> 300 -> 400 -> 500
ListNode head = new ListNode(100,
new ListNode(200, new ListNode(300,
new ListNode(400, new ListNode(500)))));
System.out.println("Middle: " + findMiddle(head).val);
}
}
Middle: 300
Why does this work?
When the fast pointer moves two steps for every one step of the slow pointer, by the time fast has traversed the full list, slow has traversed exactly half. This is a simple mathematical relationship: if fast travels distance d, slow travels d/2.
What about odd vs even length?
For odd length [1, 2, 3, 4, 5]: slow lands on 3 (the single middle).
For even length [1, 2, 3, 4]: slow lands on 3 (the second of the two middles).
// Odd: 1 -> 2 -> 3 -> 4 -> 5
// Iteration 1: slow=2, fast=3
// Iteration 2: slow=3, fast=5
// fast.next is null -> stop. slow = 3 (middle)
// Even: 1 -> 2 -> 3 -> 4
// Iteration 1: slow=2, fast=3
// Iteration 2: slow=3, fast=null
// fast is null -> stop. slow = 3 (second middle)
How to find the first middle for even lists?
Start fast at head.next instead of head, or change the loop condition to fast.next != null && fast.next.next != null.
// Second middle (standard)
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) { ... }
// For [1,2,3,4]: returns 3
// First middle (variant)
ListNode slow = head, fast = head.next;
while (fast != null && fast.next != null) { ... }
// For [1,2,3,4]: returns 2
Why does the guard order matter?
The condition fast != null && fast.next != null must check fast != null first. If fast is null, accessing fast.next would throw a NullPointerException. Java's short-circuit evaluation ensures the second check is skipped when the first fails.
// Wrong: crashes on even-length lists
while (fast.next != null && fast != null) { ... }
// fast could be null before we check fast.next
// Correct: check fast first
while (fast != null && fast.next != null) { ... }
What is the time and space complexity?
| Approach | Time | Space | Passes |
|---|---|---|---|
| Fast-slow pointer | O(n) | O(1) | 1 |
| Count length then walk half | O(n) | O(1) | 2 |
Both are O(n), but the fast-slow approach does it in a single pass.
What are common mistakes?
Reversing the guard order, which causes a NullPointerException on even-length lists.
Another mistake is forgetting that this formulation returns the second middle on even lists, when the problem asks for the first.
What are the edge cases?
- Empty list (null head): return null.
- Single node: return that node.
- Two nodes: return the second node (with standard formulation).
What should a senior engineer know?
The fast-slow skeleton is a building block. Recognizing it connects multiple problems:
- Cycle detection: if fast catches slow, there is a cycle.
- Cycle start: reset one pointer to head after detection and advance both at speed one.
- Palindrome check: find middle, reverse second half, compare.
- List splitting: use the middle to split the list into two halves for merge sort.
What are common interview follow-up questions?
- What if you need the first middle on even lists? (Start fast at head.next.)
- How does this help with merge sort on linked lists? (Split at the middle, sort both halves, merge.)
- Can you detect a cycle with this technique? (Yes, if slow and fast meet, there is a cycle.)
Visual Overview
List: 100 -> 200 -> 300 -> 400 -> 500
Start: slow = 100, fast = 100
Iteration 1: slow = 200, fast = 300
Iteration 2: slow = 300, fast = 500
fast.next = null -> STOP
Middle = slow = 300
List: 100 -> 200 -> 300 -> 400
Start: slow = 100, fast = 100
Iteration 1: slow = 200, fast = 300
Iteration 2: slow = 300, fast = null
fast = null -> STOP
Middle = slow = 300 (second of two middles)
┌──────────────────────────────────────────────┐ │ Fast-Slow Middle Finding Flow │ ├──────────────────────────────────────────────┤ │ │ │ slow = head, fast = head │ │ │ │ │ ▼ │ │ ┌────────────────────────────────┐ │ │ │ While fast != null │ │ │ │ AND fast.next != null: │ │ │ │ slow = slow.next (+1) │ │ │ │ fast = fast.next.next (+2) │ │ │ └────────────────────────────────┘ │ │ │ │ │ ▼ │ │ return slow (the middle node) │ └──────────────────────────────────────────────┘
Key Takeaway
Finding the middle of a singly linked list is the classic fast-and-slow pointer problem. Start both pointers at the head, advance slow one node and fast two nodes on each iteration. When fast reaches the end, slow is at the middle, done in a single pass without counting the length.
The guard condition fast != null && fast.next != null prevents null-pointer exceptions. The order matters: check fast first because if fast is null, accessing fast.next would crash. With this formulation, slow lands on the single middle of odd-length lists and on the second of two middles for even-length lists.
At the National Bank of India, the audit tool needed the middle transaction from a chain as a quick sampling point. The length was unknown at call time, so the single-pass fast-slow approach avoided a wasted counting pass over a long chain.
The senior-level insight is that this same skeleton underlies cycle detection, palindrome checking, and list splitting for merge sort. Recognizing the pattern across problems is the real skill.
Remember one sentence: move slow by one and fast by two; when fast finishes, slow is at the middle.
---