Find the Middle Node

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.

4 min read Level 2/5 #dsa#linked-list#two-pointers
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

ListLengthslow stops atNote
1 → 2 → 33 (odd)node 2exact middle
1 → 2 → 3 → 44 (even)node 3second 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:

  1. Find the middle with findMiddle.
  2. Reverse the second half in-place (covered in the previous lesson).
  3. Compare the first half against the reversed second half node by node.
  4. 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

OperationTimeSpace
findMiddleO(n)O(1)
isPalindromeO(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 →