Bird
Raised Fist0
Interview Prepfast-slow-pointerseasyAmazonGoogleFacebook

Middle of the Linked List

Choose your preparation mode4 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Steps
setup

Initialize slow and fast pointers at head

Both slow and fast pointers are set to the head of the list, which is the node with value 1.

💡 Starting both pointers at the head ensures they traverse the list together from the beginning.
Line:slow = head fast = head
💡 Both pointers start at the same node, ready to begin traversal.
📊
Middle of the Linked List - Watch the Algorithm Execute, Step by Step
Watching the pointers move side-by-side reveals how the fast pointer skipping nodes helps the slow pointer land exactly at the middle without counting nodes explicitly.
Step 1/10
·Active fillAnswer cell
setup
1
2
3
4
5
compare
1
2
3
4
5
advance
1
2
3
4
5
advance
1
2
3
4
5
compare
1
2
3
4
5
advance
1
2
3
4
5
advance
1
2
3
4
5
compare
1
2
3
4
5
return
1
2
3
4
5
Result: 3
done
1
2
3
4
5
Result: 3

Key Takeaways

The fast pointer moves twice as fast as the slow pointer, allowing the slow pointer to land exactly at the middle node when the fast pointer reaches the end.

This insight is difficult to grasp from code alone because the relationship between pointer speeds and the middle position is implicit.

The loop condition ensures the fast pointer never moves beyond the list bounds, preventing errors and signaling when the middle is found.

Seeing the condition visually clarifies why the loop stops exactly at the right time.

Returning the slow pointer after traversal gives the middle node without needing to count nodes or know the list length beforehand.

This shows the power of two-pointer technique to solve problems efficiently in one pass.

Practice

(1/5)
1. Given the following code snippet for detecting a circular array loop, what is the return value when the input is nums = [2, -1, 1, 2, 2]?
easy
A. True
B. False
C. Raises an IndexError
D. Infinite loop

Solution

  1. Step 1: Trace first iteration starting at index 0

    nums[0]=2 (positive), direction is forward. slow and fast start at 0.
  2. Step 2: Move slow and fast pointers

    slow moves to index (0+2)%5=2, fast moves two steps: first to 2, then to (2+1)%5=3. Both nums[2] and nums[3] are positive, direction consistent.
  3. Step 3: Next iteration

    slow moves to (2+1)%5=3, fast moves two steps: from 3 to (3+2)%5=0, then from 0 to (0+2)%5=2. slow=3, fast=2, not equal yet.
  4. Step 4: Next iteration

    slow moves to (3+2)%5=0, fast moves two steps: from 2 to (2+1)%5=3, then from 3 to (3+2)%5=0. slow=0, fast=0, pointers meet.
  5. Step 5: Check cycle length

    Check if slow == next_index(slow): next_index(0) = 2, not equal, so cycle length > 1.
  6. Final Answer:

    Option A -> Option A
  7. Quick Check:

    Cycle detected with consistent direction and length > 1 [OK]
Hint: Pointers meet at index 0 with valid cycle -> returns True [OK]
Common Mistakes:
  • Confusing slow and fast pointer positions
  • Ignoring direction check
  • Mistaking single-element loop as valid
2. Examine the following buggy code for cycle detection using fast and slow pointers. Which line contains the subtle bug that can cause incorrect cycle detection or runtime error?
medium
A. Line 3: while fast and fast.next:
B. Line 5: slow = slow.next
C. Line 6: fast = fast.next.next
D. Line 4: if slow == fast:

Solution

  1. Step 1: Understand pointer initialization and loop

    Both slow and fast start at head. The loop checks fast and fast.next to avoid null dereference.
  2. Step 2: Identify when pointers are compared

    Comparing slow == fast before moving pointers causes immediate true at start (both at head), falsely detecting a cycle. Moving pointers first then comparing avoids this.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Comparison must happen after moving pointers to avoid false positive [OK]
Hint: Check pointers after moving, not before, to avoid false positives [OK]
Common Mistakes:
  • Comparing pointers before moving them
  • Not checking fast.next before advancing fast
3. Examine the following code snippet intended to detect the start of a cycle in a linked list. Identify the line containing the subtle bug that can cause a runtime error or infinite loop.
medium
A. Line 5: fast = fast.next.next
B. Line 3: while fast:
C. Line 7: if slow == fast:
D. Line 11: while ptr1 != ptr2:

Solution

  1. Step 1: Check loop condition safety

    The loop condition only checks if fast is not None, but fast.next may be None, so fast.next.next can cause an exception.
  2. Step 2: Identify fix

    The loop condition should check both fast and fast.next to avoid null pointer exceptions.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Accessing fast.next.next without checking fast.next causes runtime error [OK]
Hint: Always check fast and fast.next before accessing fast.next.next [OK]
Common Mistakes:
  • Missing fast.next check
  • Returning meeting point as cycle start
  • Infinite loop due to wrong loop condition
4. What is the space complexity of the recursive reorderList implementation shown below, considering a linked list of length n?
medium
A. O(log n) -- recursion divides list in halves
B. O(1) -- only constant extra pointers used
C. O(n) -- recursion stack grows linearly with list length
D. O(n^2) -- nested recursive calls cause quadratic space

Solution

  1. Step 1: Analyze recursion depth

    Each recursive call moves one node forward, so recursion depth is n.
  2. Step 2: Determine space usage

    Each call adds a stack frame, so total auxiliary space is O(n).
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Recursion stack grows linearly with input size [OK]
Hint: Recursion depth equals list length -> O(n) space [OK]
Common Mistakes:
  • Assuming recursion is O(1) space
  • Confusing recursion with divide-and-conquer
  • Thinking nested calls multiply space
5. Suppose the Happy Number problem is extended to allow negative integers as input. Which modification to the optimal algorithm is necessary to correctly handle negative inputs?
hard
A. Add absolute value conversion before processing digits to handle negatives
B. Add negative numbers to the cycle set to detect cycles
C. Modify get_next to handle negative digits separately
D. No change needed; negative numbers will eventually reach 1 or cycle

Solution

  1. Step 1: Understand digit extraction for negative numbers

    Digit extraction using modulo and division assumes non-negative numbers. Negative inputs cause incorrect digit processing.
  2. Step 2: Convert input to absolute value before processing

    Taking absolute value ensures digits are correctly extracted and sum of squares computed properly.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Absolute value fixes digit extraction for negatives [OK]
Hint: Digit extraction requires non-negative numbers [OK]
Common Mistakes:
  • Assuming negative inputs work without modification