Given a singly linked list, find and return its middle node. If there are two middle nodes, return the second one.
Output: Node 4
Output: Node 4
New to this one? Start here. Below is the core idea in everyday language, plus a real-world analogy—then the sections that follow build on it with the formal reasoning, code, and step-by-step walkthroughs.
You and a friend start at one end of a hallway. You take single steps; your friend takes double steps. The instant your friend reaches the far wall, you are standing exactly in the middle of the hallway — you never had to measure its length first.
The most intuitive approach to solve this problem is to traverse the linked list to find its length (n), and then traverse the linked list a second time to find the middle node (n / 2):
This approach solves the problem in time, but requires two iterations to find the midpoint. However, there’s a cleaner approach that uses only a single iteration.
When iterating through the linked list, our exact position is unclear. We only know where we are when we reach the final node. Is it possible to create a scenario where, as soon as one pointer reaches the end of the linked list, the other pointer is positioned at the middle node?
If we had one pointer move at half the speed of the other, by the time the faster pointer reaches the end of the list, the slower one will be at the middle of the linked list.
We can achieve this by using the fast and slow pointer technique:
One thing we must be careful about is when we should stop advancing the fast pointer. We need to stop when the slow pointer reaches the middle node. When the list length is odd, this happens when fast.next equals null, as we can see above.
What about when the length of the linked list is even? Consider the below example:
As you can see, to have slow point at the second middle node, we'd need to stop fast when it reaches a null node.
from ds import ListNode
def linked_list_midpoint(head: ListNode) -> ListNode:
slow = fast = head
# When the fast pointer reaches the end of the list, the slow pointer will be at
# the midpoint of the linked list.
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slowListNode* linkedListMidpoint(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next; // one step
fast = fast->next->next; // two steps
}
return slow; // slow is the middle
}public ListNode linkedListMidpoint(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next; // one step
fast = fast.next.next; // two steps
}
return slow; // slow is the middle
}Time complexity: The time complexity of linked_list_midpoint is because we traverse the linked list linearly using two pointers.
Space complexity: The space complexity is .
What if you were asked to modify your algorithm to return the first middle node when the linked list is of even length?
Answer: Following the same method, we should stop advancing the fast pointer when fast.next.next is null. This way, slow will end up pointing to the first middle node:
Two step-by-step walkthroughs of the algorithm below: a valid case (the expected happy path) and an invalid / edge case that exercises the tricky parts. Each step shows the program state as the code runs—the same steps apply to Python, C++ and Java.
slow (+1) fast (+2)
| iteration | slow | fast | continue? |
|---|---|---|---|
| start | 1 | 1 | fast.next ok |
| 1 | 2 | 3 | fast.next ok |
| 2 | 3 | 5 | fast.next null → stop, return 3 |
slow (+1) fast (+2)
fast is null → stop.
| iteration | slow | fast | continue? |
|---|---|---|---|
| start | 1 | 1 | fast.next ok |
| 1 | 2 | 3 | fast.next ok |
| 2 | 3 | 5 | fast.next ok |
| 3 | 4 | null | fast null → stop, return 4 |
Contrast with Dry run 1: an odd list has one exact middle, so slow lands on it while fast stops on the last node. An even list has two middles (here 3 and 4); the guard lets the hare take one more pair of steps, so slow advances to the second middle (4). Loop while fast.next and fast.next.next if you want the first.
Both runs step exactly as the tables above. Python loops while fast is not None and fast.next is not None and returns slow.
Same steps. C++: while (fast && fast->next); return slow.
Same steps. Java: while (fast != null && fast.next != null); return slow.
Tip: Be prepared to address potential gaps in the information provided.
During an interview, it’s possible the interviewer won't specify which middle node should be returned for linked lists of even length, leaving it up to you to recognize and address this special scenario. You might be expected to identify ambiguities like this and actively engage with the interviewer to discuss a suitable resolution.