Linked List Data Structure: Master Fast-Slow Pointer Technique for Interviews
Complete guide to linked list problems with two-pointer patterns. Learn Floyd's cycle detection, reverse operations, and pointer manipulation. Ace linked list coding interviews with proven Python techniques

The Day I Finally "Got" Linked Lists
I used to dread linked list problems in interviews. The pointer manipulation felt like mental gymnastics—one wrong move and you'd lose track of nodes, create infinite loops, or worse, get a dreaded null pointer exception. Then someone showed me the "fast and slow pointer" technique, and everything clicked.
That single technique—having two pointers moving at different speeds—unlocked solutions to problems I thought were impossibly complex. Detecting cycles? Fast and slow pointers. Finding the middle? Fast and slow pointers. Checking for palindromes? You guessed it—fast and slow pointers.
In this guide, I'll share the systematic approach that transformed linked lists from my weakness to one of my strengths. You'll learn the core patterns that solve 90% of linked list problems, with clear intuition and practical examples.
Why Linked Lists Trip People Up
Linked lists feel harder than arrays for a simple reason: you can't randomly access elements. With an array, you can jump to arr[5] instantly. With a linked list, you have to walk through nodes 0, 1, 2, 3, 4 to reach node 5.
This fundamental constraint shapes everything about linked list algorithms:
- No binary search (can't jump to middle)
- Must traverse sequentially
- Pointer manipulation requires careful ordering
- Easy to lose references and create memory leaks
But here's the thing: once you learn the core patterns, linked lists become predictable. Every problem is just a variation of 4-5 techniques.
The Core Linked List Patterns
Pattern 1: The Two-Pointer (Fast and Slow) Technique
This is THE most important linked list pattern. Master this, and you've solved half of all linked list problems.
The concept: Use two pointers moving at different speeds through the list. The "slow" pointer moves one step at a time, the "fast" pointer moves two steps.
When to use:
- Finding the middle of a list
- Detecting cycles
- Finding the kth node from the end
- Checking for palindromes
The basic template:
def two_pointer_pattern(head):
"""
Basic two-pointer template.
Fast moves 2x speed of slow.
"""
slow = head
fast = head
while fast and fast.next:
slow = slow.next # Move 1 step
fast = fast.next.next # Move 2 steps
# When fast reaches end, slow is at middle
return slow
Why it works: When fast has traversed the entire list (2n steps), slow has only traversed n steps—exactly halfway through.
Example: Find Middle of Linked List
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def find_middle(head):
"""
Find middle node using fast and slow pointers.
When fast reaches end, slow is at middle.
"""
if not head:
return None
slow = head
fast = head
# Fast moves 2 steps, slow moves 1 step
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow # Slow is now at middle
Test: For list 1 → 2 → 3 → 4 → 5, returns node with value 3
Key insight: This gives us O(n) time with O(1) space—no need to count nodes first or use extra memory.
Example: Detect Cycle in Linked List (Floyd's Algorithm)
LeetCode #141 - Linked List Cycle
This is one of the most elegant algorithms in computer science.
def has_cycle(head):
"""
Detect cycle using Floyd's cycle detection.
If fast catches slow, there's a cycle.
"""
if not head or not head.next:
return False
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# If pointers meet, cycle exists
if slow == fast:
return True
return False # Fast reached end, no cycle
Why it works: If there's a cycle, fast will eventually lap slow and they'll meet. If there's no cycle, fast reaches the end (None).
The intuition: Think of two runners on a circular track—the faster one will eventually catch up to the slower one if they're running in circles. If the track has an end, the fast runner just reaches it first.
Example: Find Nth Node from End
LeetCode #19 - Remove Nth Node From End
This uses a variation: advance one pointer n steps ahead, then move both at the same speed.
def find_nth_from_end(head, n):
"""
Find nth node from end using two pointers.
Advance first pointer n steps, then move both together.
"""
# Create dummy node to handle edge cases
dummy = ListNode(0)
dummy.next = head
first = dummy
second = dummy
# Advance first pointer n+1 steps ahead
for _ in range(n + 1):
first = first.next
# Move both pointers until first reaches end
while first:
first = first.next
second = second.next
# Second is now at (n+1)th node from end
# Remove nth node
second.next = second.next.next
return dummy.next
Key insight: By keeping pointers n steps apart, when the first reaches the end, the second is exactly n steps from the end.
Pattern 2: Reversal Techniques
Reversing a linked list is fundamental. Many problems require reversing the whole list or parts of it.
Basic Reversal (Iterative)
def reverse_list(head):
"""
Reverse linked list iteratively.
Use three pointers: prev, curr, next.
"""
prev = None
curr = head
while curr:
# Save next node
next_node = curr.next
# Reverse current node's pointer
curr.next = prev
# Move pointers forward
prev = curr
curr = next_node
return prev # New head
The mantra: "Save next, reverse current, move forward"
Visual walkthrough for 1 → 2 → 3:
Step 0: None ← 1 2 → 3
Step 1: None ← 1 ← 2 3
Step 2: None ← 1 ← 2 ← 3
Time: O(n), Space: O(1)
Reverse in Groups of K
LeetCode #25 - Reverse Nodes in k-Group
def reverse_k_group(head, k):
"""
Reverse every k nodes in the list.
More complex: need to connect reversed groups.
"""
# Helper: reverse k nodes starting from head
def reverse_k(head, k):
prev = None
curr = head
count = 0
while curr and count < k:
next_node = curr.next
curr.next = prev
prev = curr
curr = next_node
count += 1
return prev, head, curr # new_head, new_tail, next_group_head
# Check if we have k nodes remaining
def has_k_nodes(node, k):
count = 0
while node and count < k:
node = node.next
count += 1
return count == k
dummy = ListNode(0)
dummy.next = head
prev_group_tail = dummy
while has_k_nodes(prev_group_tail.next, k):
# Reverse this group
group_head = prev_group_tail.next
new_head, new_tail, next_head = reverse_k(group_head, k)
# Connect with previous group
prev_group_tail.next = new_head
new_tail.next = next_head
# Move to next group
prev_group_tail = new_tail
return dummy.next
Key insight: We need to track multiple things: the tail of the previous group (to connect), the head and tail of the current group, and the head of the next group.
Pattern 3: The Dummy Head Technique
Many linked list problems become simpler when you use a "dummy" node before the actual head.
Why dummy nodes help:
- Simplify edge cases (empty list, single node)
- Make deletion easier (no special case for deleting head)
- Provide a stable reference when head changes
def remove_elements(head, val):
"""
Remove all nodes with given value.
Dummy node simplifies deletion logic.
"""
dummy = ListNode(0)
dummy.next = head
curr = dummy
while curr.next:
if curr.next.val == val:
# Delete next node
curr.next = curr.next.next
else:
curr = curr.next
return dummy.next # Return actual head
Without dummy node, we'd need:
# Handle head deletion separately
while head and head.val == val:
head = head.next
# Then handle rest of list...
Much messier!
Pattern 4: Merge Techniques
Merging sorted lists is a common pattern, from simple two-list merges to complex k-list merges.
Merge Two Sorted Lists
LeetCode #21 - Merge Two Sorted Lists
def merge_two_lists(l1, l2):
"""
Merge two sorted lists into one sorted list.
Use dummy node and compare values.
"""
dummy = ListNode(0)
curr = dummy
while l1 and l2:
if l1.val <= l2.val:
curr.next = l1
l1 = l1.next
else:
curr.next = l2
l2 = l2.next
curr = curr.next
# Attach remaining nodes
curr.next = l1 if l1 else l2
return dummy.next
Key insight: We're building a new list by choosing the smaller value at each step. The dummy node gives us a starting point.
Merge K Sorted Lists
LeetCode #23 - Merge k Sorted Lists
import heapq
def merge_k_lists(lists):
"""
Merge k sorted lists using min heap.
Heap tracks smallest current value from each list.
"""
# Initialize min heap with first node from each list
heap = []
for i, node in enumerate(lists):
if node:
# (value, list_index, node) - list_index for tie-breaking
heapq.heappush(heap, (node.val, i, node))
dummy = ListNode(0)
curr = dummy
while heap:
val, i, node = heapq.heappop(heap)
# Add smallest node to result
curr.next = node
curr = curr.next
# Add next node from same list to heap
if node.next:
heapq.heappush(heap, (node.next.val, i, node.next))
return dummy.next
Time: O(N log k) where N = total nodes, k = number of lists Space: O(k) for the heap
Key insight: Using a heap, we always know the globally smallest unprocessed node across all k lists. Much better than pairwise merging (which would be O(N k)).
Pattern 5: Palindrome Checking
Checking if a linked list is a palindrome combines multiple patterns.
LeetCode #234 - Palindrome Linked List
def is_palindrome(head):
"""
Check if linked list is palindrome.
Strategy: Find middle, reverse second half, compare.
"""
if not head or not head.next:
return True
# Step 1: Find middle using fast and slow pointers
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# Step 2: Reverse second half
second_half = reverse_list(slow)
# Step 3: Compare first and second halves
first_half = head
while second_half:
if first_half.val != second_half.val:
return False
first_half = first_half.next
second_half = second_half.next
return True
def reverse_list(head):
"""Helper: reverse linked list."""
prev = None
curr = head
while curr:
next_node = curr.next
curr.next = prev
prev = curr
curr = next_node
return prev
The strategy:
- Find middle (fast & slow pointers)
- Reverse second half (reversal pattern)
- Compare both halves node by node
Time: O(n), Space: O(1)
Key insight: This problem showcases how patterns combine. We use two-pointer to find middle, reversal to flip second half, and simple traversal to compare.
Advanced Pattern: Intersection and Union
Finding where two lists intersect is a beautiful problem with an elegant solution.
LeetCode #160 - Intersection of Two Linked Lists
def get_intersection_node(headA, headB):
"""
Find intersection point of two lists.
Clever trick: traverse both lists, then swap.
"""
if not headA or not headB:
return None
pA, pB = headA, headB
# Traverse both lists
while pA != pB:
# When reaching end, jump to other list's head
pA = pA.next if pA else headB
pB = pB.next if pB else headA
return pA # Either intersection node or None
Why this works:
If lists intersect:
- After swapping, both pointers travel same total distance
- They meet at intersection
If lists don't intersect:
- Both become None at same time
Visual for intersecting lists:
A: 1 → 2 → 3 ↘
8 → 9 → None
B: 4 → 5 ↗
A's journey: 1→2→3→8→9→None→4→5→8 (meets at 8)
B's journey: 4→5→8→9→None→1→2→3→8 (meets at 8)
Both travel same distance: (lenA + lenB). Brilliant!
Common Linked List Pitfalls
Mistake 1: Losing References
# WRONG: Lost reference to rest of list
node.next = new_node
# Original node.next nodes are now inaccessible!
# RIGHT: Save reference first
temp = node.next
node.next = new_node
new_node.next = temp
Mistake 2: Not Handling Null Pointers
# WRONG: Will crash if node is None
if node.next.val == target:
# RIGHT: Check for null first
if node and node.next and node.next.val == target:
Mistake 3: Forgetting Edge Cases
Always test:
- Empty list (head = None)
- Single node
- Two nodes
- Target at head
- Target at tail
Mistake 4: Modifying While Traversing
# WRONG: Deleting while iterating without saving next
curr = head
while curr:
if should_delete(curr):
delete(curr)
curr = curr.next # curr is deleted, curr.next crashes!
# RIGHT: Save next before any modification
while curr:
next_node = curr.next
if should_delete(curr):
delete(curr)
curr = next_node
The Linked List Decision Tree
When you see a linked list problem:
1. Does it involve finding a position?
- Middle node → Fast & slow pointers
- Nth from end → Advance first n steps, move both
- Cycle detection → Floyd's algorithm
2. Does it involve reversing?
- Entire list → Iterative reversal with three pointers
- In groups → Reversal + careful reconnection
- Palindrome check → Find middle + reverse second half
3. Does it involve merging?
- Two sorted lists → Two pointers, compare values
- K sorted lists → Min heap for efficiency
4. Does it involve deletion?
- Use dummy node to simplify edge cases
- Always save next pointer before deleting
5. Does it involve intersection or cycles?
- Intersection → Swap heads after reaching end
- Cycle detection → Fast & slow pointers
My Practice Strategy
Here's how I mastered linked lists:
Week 1: Master the Basics
- Implement basic operations 10 times: reverse, find middle, detect cycle
- Draw pictures for each step
- Practice without looking at code
Week 2: Two-Pointer Variations
- Solve 15-20 problems using fast & slow pointers
- Focus on recognizing when to use this technique
- Practice edge cases
Week 3: Complex Manipulations
- Reverse in groups
- Merge multiple lists
- Palindrome checking
- Rearrangement problems
Week 4: Mixed Practice
- 30-40 problems of varying difficulty
- Time yourself: recognize pattern in 30 seconds
- Code solution in 15 minutes
Real Interview Success
I was asked: "Reorder a linked list so all odd-indexed nodes come before even-indexed nodes."
My approach:
- Recognized pattern: Split into two lists (odd and even positions)
- Use two pointers to build odd and even lists
- Connect odd list tail to even list head
Coded in 12 minutes:
def odd_even_list(head):
if not head or not head.next:
return head
odd = head
even = head.next
even_head = even # Save even list head
while even and even.next:
# Link next odd node
odd.next = even.next
odd = odd.next
# Link next even node
even.next = odd.next
even = even.next
# Connect odd tail to even head
odd.next = even_head
return head
The interviewer was impressed by how I immediately identified the pattern and handled edge cases.
Conclusion: Your Linked List Mastery Roadmap
Linked lists aren't as scary as they seem. Here's what matters:
- Master fast & slow pointers - Solves 50% of problems
- Practice reversal until it's muscle memory - Core building block
- Always use dummy nodes - Simplifies edge cases
- Draw pictures - Visualize pointer changes
- Handle null pointers - Check before accessing
Start with basic traversal and reversal. Once those feel natural, move to two-pointer techniques. Finally, combine patterns for complex problems.
Within 3-4 weeks of focused practice, you'll handle linked list problems with confidence.
Remember: every expert once struggled with pointer manipulation. The difference is they practiced until the patterns became automatic.
Happy coding, and may your pointers always point true!
If you found this guide helpful, share it with others learning data structures. Linked lists are fundamental—mastering them makes you a better programmer. If this guide helped you master linked list patterns or ace your coding interview, I'd love to hear about it! Connect with me on Twitter or LinkedIn.
Support My Work
If this guide helped you finally understand linked lists, gave you confidence with pointer manipulation, or helped you ace coding interviews, I'd really appreciate your support! Creating comprehensive, free content like this takes significant time and effort. Your support helps me continue sharing knowledge and creating more helpful resources for students like you.
☕ Buy me a coffee - Every contribution, big or small, means the world to me and keeps me motivated to create more content!