Welcome to our next lesson on linked lists. In our previous session, you mastered pointer manipulation by learning to reverse a linked list iteratively and recursively. That was a crucial exercise in understanding how to rewire the fundamental connections within the list. Today, we will build on that foundation by exploring a powerful problem-solving pattern: the slow-fast pointer technique.
This lesson addresses the classic interview problem of finding the middle node of a singly linked list. True to your preferred learning style, we will first examine a straightforward brute-force solution and analyze its limitations. Then, we will dive deep into the elegant and efficient slow-fast pointer approach, which is the optimal solution you'll be expected to know. This pattern is not just a one-trick pony; it's a versatile tool that you'll use to solve other key linked list problems.
1. Brute-Force: The Two-Pass Approach
When faced with finding the middle of a list, the most immediate challenge is that we don't know its length. A simple and direct way to solve this is to first find the length, and then use that information to locate the middle element. This method involves two separate traversals of the list.
The algorithm is as follows:
- First Pass: Traverse the entire linked list from head to tail, counting the number of nodes. Let's call this count
n. - Calculate Middle: The problem states that if there are two middle nodes (in an even-length list), we should return the second one. The index of this middle node can be found by
n / 2. For a list of 5 nodes,5 / 2 = 2(integer division), so we need the node at index 2 (the 3rd node). For a list of 6 nodes,6 / 2 = 3, so we need the node at index 3 (the 4th node). - Second Pass: Traverse the list again from the
head, this time stopping aftern / 2steps. The node you land on is the middle node.
To see this approach explained, let's turn to a video from the takeUforward channel.
L13. Find the middle element of the LinkedList | Multiple Approaches
This video segment by Striver introduces the brute-force, two-pass solution. It's a great starting point for understanding the problem before we optimize.
Watch the explanation of this method from this segment. Pay attention to how the length n is first calculated and then used in a second traversal to find the middle node.
You can also review this method in the text below, which provides a Java implementation for reference.
This article from GeeksforGeeks describes the two-pass method clearly.
Read the section titled Naive Approach. You can skim the C++ code and focus on the Java implementation provided, as it directly reflects the logic discussed.
This approach is correct, but it's not optimal. Its time complexity is O(n) because of the two passes (O(n) + O(n/2)), and its space complexity is O(1). In an interview, you'd be asked if you can do better. Specifically, can you find the middle in just a single pass? The answer is yes, and that brings us to the optimal solution.
2. The Optimal Approach: Slow and Fast Pointers
The slow-fast pointer technique, often called the "Tortoise and Hare" algorithm, is a clever way to solve this problem in a single pass. The intuition is simple yet powerful.
Imagine two pointers traversing the list from the head:
- A
slowpointer that moves one step at a time (slow = slow.next). - A
fastpointer that moves two steps at a time (fast = fast.next.next).
By the time the fast pointer reaches the end of the list, the slow pointer will have traveled exactly half the distance, naturally positioning it at the middle node.
The following video provides an excellent intuition and a visual dry run of this technique.
L13. Find the middle element of the LinkedList | Multiple Approaches
This part of the video explains the "Tortoise and Hare" algorithm. The visualization for both odd and even length lists is particularly helpful.
Please watch the explanation of the optimal approach starting from this point. Notice the key difference in where the fast pointer stops for odd versus even length lists.
Let's break down the logic for both cases.
Case 1: Odd Number of Nodes
Consider a list: 1 -> 2 -> 3 -> 4 -> 5
- Initial:
slowis at 1,fastis at 1. - Step 1:
slowmoves to 2,fastmoves to 3. - Step 2:
slowmoves to 3,fastmoves to 5. - At this point,
fastis at the last node. We can't move it two steps further becausefast.nextisnull. The loop terminates, andslowis correctly positioned at node 3, the middle.
Case 2: Even Number of Nodes
Consider a list: 1 -> 2 -> 3 -> 4 -> 5 -> 6
- Initial:
slowis at 1,fastis at 1. - Step 1:
slowmoves to 2,fastmoves to 3. - Step 2:
slowmoves to 3,fastmoves to 5. - Step 3:
slowmoves to 4,fastmoves past 6 tonull. - Now,
fastisnull. The loop terminates, andslowis at node 4, which is the second middle node as required by the problem.
The crucial part of this algorithm is the loop condition: while (fast != null && fast.next != null). This single condition elegantly handles both odd and even length lists.
fast.next != nullhandles the odd-length case. Whenfastis on the last node,fast.nextisnull, and the loop stops.fast != nullhandles the even-length case. Afterfastis on the second-to-last node, its next move (fast.next.next) will land it onnull. The check prevents aNullPointerExceptionon the subsequentfast.next.
For a deeper dive into the algorithm, its implementation, and common pitfalls, the following reading is highly recommended.
876. Middle of the Linked List - In-Depth Explanation
This AlgoMonster article provides a comprehensive breakdown of the slow-fast pointer technique.
Please read through the article. Start with the Intuition section, which uses a runner analogy. Then, carefully study the Algorithm Steps and the provided Java implementation under Solution Implementation. Finally, the article provides an excellent analysis of the complexity.
This single-pass approach is highly efficient. The time complexity is O(n/2), which simplifies to O(n), and the space complexity is a constant O(1) as we only use two extra pointers.
Practice Problem
Now it's your turn to put this pattern into practice. Use the slow-fast pointer technique to solve the problem on LeetCode.
Try to code the solution in Java from scratch, keeping the logic and the critical loop condition in mind.
Conclusion
In this lesson, we explored a fundamental linked list pattern—the slow-fast pointer technique—to efficiently find the middle node. This pattern is a significant step up from basic traversal and showcases a more advanced way of thinking about pointer-based problems.
Key Takeaways:
- Brute-Force: A two-pass approach that first finds the length and then traverses to the middle. It's functional but suboptimal.
- Optimal (Slow-Fast Pointers): A single-pass, O(n) time and O(1) space solution. It uses a
slowpointer (1 step) and afastpointer (2 steps). - The Core Logic: When the
fastpointer reaches the end of the list (ornull), theslowpointer is guaranteed to be at the middle. - The Critical Condition: The
while (fast != null && fast.next != null)condition is key to making the algorithm work for both odd and even length lists without errors.
This slow-fast pointer pattern is not just for finding the middle. In our next lesson, we will apply this very same technique to solve another classic and important problem: detecting a cycle in a linked list.