876. Middle of the Linked List - Explanation

Problem Link

Description

You are 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.

Example 1:

Input: head = [1,2,3,4,5]

Output: [3,4,5]

Example 2:

Input: head = [1,2,3,4,5,6]

Output: [4,5,6]

Constraints:

  • 1 <= The length of the list <= 100
  • 1 <= Node.val <= 100


Topics

Company Tags

Please upgrade to NeetCode Pro to view company tags.



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Linked Lists - Understanding node structure with value and next pointer, and how to traverse a linked list
  • Two Pointers (Fast & Slow) - The technique of using two pointers moving at different speeds to find middle elements or detect cycles
  • Arrays - Using dynamic arrays to store elements for indexed access

1. Convert To Array

Intuition

Linked lists do not support random access, so finding the middle node directly is not straightforward. By storing all nodes in an array, we gain index-based access. Once we have the array, the middle node is simply at index length / 2.

Algorithm

  1. Traverse the linked list and store each node in an array.
  2. Calculate the middle index as length / 2.
  3. Return the node at the middle index.
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
        cur = head
        arr = []
        while cur:
            arr.append(cur)
            cur = cur.next
        return arr[len(arr) // 2]

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

2. Find Length of the List

Intuition

We can avoid storing all nodes by first counting the total number of nodes, then making a second pass to reach the middle. This uses constant extra space since we only store the count and a pointer.

Algorithm

  1. Traverse the list once to count the total number of nodes n.
  2. Calculate the middle position as n / 2.
  3. Traverse the list again, moving forward n / 2 steps from the head.
  4. Return the node at that position.
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
        n, cur = 0, head
        while cur:
            cur = cur.next
            n += 1

        n //= 2
        cur = head
        while n:
            n -= 1
            cur = cur.next
        return cur

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(1)O(1) extra space.

3. Fast & Slow Pointers

Intuition

The fast and slow pointer technique finds the middle in a single pass. The slow pointer moves one step at a time, while the fast pointer moves two steps. When the fast pointer reaches the end, the slow pointer will be at the middle. This works because the fast pointer covers twice the distance in the same number of iterations.

Algorithm

  1. Initialize both slow and fast pointers at the head.
  2. While fast is not null and fast.next is not null:
    • Move slow one step forward.
    • Move fast two steps forward.
  3. Return slow, which now points to the middle node.
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
        slow, fast = head, head

        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
        return slow

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(1)O(1) extra space.

Common Pitfalls

Incorrect Loop Condition for Fast Pointer

When using the fast and slow pointer technique, the loop condition must check both fast and fast.next before advancing. Checking only fast can cause a null pointer exception when trying to access fast.next.next. The correct condition is while (fast != null && fast.next != null).

Off-by-One Error with Even-Length Lists

For lists with an even number of nodes, there are two middle nodes. The problem typically asks for the second middle node, but some implementations accidentally return the first. Ensure your pointer movement logic returns the correct middle based on the problem requirements.