Slow and Fast Pointers Locate the Middle in One Pass With O(1) Space
Find the Middle Node
Apply the slow/fast pointer pattern to find the middle node of a linked list in a single traversal, then use it to check whether a list is a palindrome.
What you'll learn
- Find the middle node of a linked list using two pointers moving at different speeds
- Handle even-length lists and explain the two possible midpoint conventions
- Combine middle-finding with list reversal to check for palindromes
Finding the middle node of a linked list without knowing its length seems to require two passes — one to count, one to walk halfway. The slow/fast pointer pattern does it in a single pass.
Node Class
class ListNode {
constructor(val = 0, next = null) {
this.val = val;
this.next = next;
}
} The Algorithm
Move slow one step and fast two steps at every iteration. When fast
reaches the end, slow is at the middle.
function findMiddle(head) {
let slow = head;
let fast = head;
while (fast !== null && fast.next !== null) {
slow = slow.next;
fast = fast.next.next;
}
return slow; // middle node
} Even vs Odd Length
| List | Length | slow stops at | Note |
|---|---|---|---|
| 1 → 2 → 3 | 3 (odd) | node 2 | exact middle |
| 1 → 2 → 3 → 4 | 4 (even) | node 3 | second of two midpoints |
If you need the first midpoint of an even-length list, stop one step
earlier by checking fast.next.next before advancing:
function findFirstMiddle(head) {
let slow = head;
let fast = head;
while (fast.next !== null && fast.next.next !== null) {
slow = slow.next;
fast = fast.next.next;
}
return slow; // first of two midpoints for even-length lists
} Application — Palindrome Linked List
A sequence is a palindrome if it reads the same forwards and backwards. For a linked list:
- Find the middle with
findMiddle. - Reverse the second half in-place (covered in the previous lesson).
- Compare the first half against the reversed second half node by node.
- Optionally restore the list by reversing again.
function reverseList(head) {
let prev = null;
let curr = head;
while (curr) {
const next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
function isPalindrome(head) {
if (!head || !head.next) return true;
// Step 1: find middle
const mid = findMiddle(head);
// Step 2: reverse second half
let secondHalf = reverseList(mid.next);
mid.next = null; // cut the list
// Step 3: compare
let p1 = head;
let p2 = secondHalf;
let result = true;
while (p2) {
if (p1.val !== p2.val) { result = false; break; }
p1 = p1.next;
p2 = p2.next;
}
// Step 4: restore (good practice)
mid.next = reverseList(secondHalf);
return result;
}
// Test: 1 → 2 → 3 → 2 → 1
const n5 = new ListNode(1);
const n4 = new ListNode(2, n5);
const n3 = new ListNode(3, n4);
const n2 = new ListNode(2, n3);
const n1 = new ListNode(1, n2);
console.log(isPalindrome(n1)); // true Complexity
| Operation | Time | Space |
|---|---|---|
| findMiddle | O(n) | O(1) |
| isPalindrome | O(n) | O(1) |
Up Next
Merge two sorted linked lists into one sorted list using a dummy-head pointer — the foundation of merge sort on linked lists.
Merge Sorted Lists →