Skip to content

The Middle Meets You There

Instead, the whole community grew frantic searching for the missing middle while two pointers found it by running the same road at different speeds—again. Today I understood that idea better than I could demonstrate it. After four days of sleeping three or four hours a night, I volunteered to solve a familiar linked-list problem and basically blanked out. The algorithm was simple. My brain was not.


Today's problem was 876. Middle of the Linked List. Given the head of a singly linked list, the function has to return its middle node. If the list has an even number of nodes and therefore has two possible middles, it has to return the second one.

The solution uses the same slow-and-fast-pointer pattern I used recently for cycle detection:

class Solution:
    def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
        slow = head
        fast = head

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

        return slow

One Pointer Measures the Other

Both pointers begin at the head:

slow = head
fast = head

On every iteration, slow moves one node and fast moves two:

slow = slow.next
fast = fast.next.next

The important relationship is not where either pointer is by itself. It is how far one has traveled compared with the other. Every time fast covers two nodes, slow covers one. By the time fast has crossed the whole list, slow has crossed half of it.

For an odd-length list like [1, 2, 3, 4, 5], the pointers move like this:

Step slow fast
Start 1 1
1 2 3
2 3 5

At node 5, fast.next is None, so the loop stops. slow is sitting on node 3, the middle.

This avoids counting the nodes first and then traversing the list a second time. The two pointers measure the length and locate the midpoint during the same pass.

Why It Returns the Second Middle

The even-length case is the clever part. For [1, 2, 3, 4, 5, 6], the pointers move like this:

Step slow fast
Start 1 1
1 2 3
2 3 5
3 4 None

There are two middle nodes, 3 and 4. The third iteration is still allowed because fast is on node 5 and node 6 exists after it. slow advances from 3 to 4, while fast moves past the end and becomes None.

That means the loop condition automatically produces the behavior the prompt asks for. I do not need a separate even-length check or an adjustment after the loop. Starting both pointers at the head and continuing while two steps remain puts slow on the second middle.

The Guard Makes the Jump Safe

Moving two nodes at once creates a risk:

fast = fast.next.next

If fast does not exist, I cannot access fast.next. If fast.next does not exist, there is no second step to take. The loop checks both conditions before moving:

while fast and fast.next:

Python evaluates the expression from left to right and short-circuits it. When fast is None, Python stops before attempting to read fast.next.

The condition also handles both ways a list can end. In an odd-length list, fast finishes on the last node, whose next is None. In an even-length list, fast moves beyond the last node and becomes None. Either way, the loop stops safely.

Returning a Node, Not a Value

The function returns slow itself:

return slow

It does not return slow.val. LeetCode asks for the middle node, and that node is still connected to everything after it. For the input [1, 2, 3, 4, 5], returning the node containing 3 gives LeetCode the linked list:

[3, 4, 5]

That distinction is easy to miss when the examples display numbers. A linked-list problem is usually asking me to work with the structure, not merely extract one value from it.

The final complexity is O(n) time and O(1) extra space. Each pointer only moves forward, and the algorithm does not build another collection to remember what it has seen.

Code Platoon — Week 14, Day 64

Today was brutally busy, especially after last night. I sacrificed the weekend to finish an audiobook and did finish it, but not until around 2:30 or 2:45 in the morning. Then I woke up at five. It has been four days of perpetual fog, and there were moments today when I would just freeze, almost stunned from lack of sleep.

That was the state I was in when I volunteered for the morning algorithm. I thought it might be one of my last chances to do one in front of the class. Instead, we learned that algorithms are going to be a much larger part of these final two weeks—possibly four a day in addition to the group project.

From a job-preparation standpoint, I understand the reasoning. This is probably the last chance the program has to drill these patterns into us, and most people are unlikely to keep practicing them unless an interview forces the issue. From a student standpoint, it felt like a math teacher announcing daily problem sets immediately before the final project is due.

The problem was somewhat familiar, but I had made a bad call volunteering on almost no sleep. I blanked. I eventually got to the solution with a lot of nudging, but it was a poor showing. The frustrating part is that the technique was not new. Only a few days ago, I used slow and fast pointers to detect a linked-list cycle. Today, the same relative motion found a midpoint instead of a loop.

That is a useful reminder about the difference between recognizing an explanation and producing a solution on demand. I can understand why the code works once it is in front of me. I can trace every pointer movement and explain the even-length case. Retrieval under pressure is a separate skill, and sleep deprivation makes that gap much wider.

The smoother part of the day was the group project. Young Money, our finance app, moved forward steadily. The work divided naturally between the back end and front end, and I spent my time on the side of the project where I am strongest. We worked through the deliverables, got everything done by the end of the day, and kept the project on track.

I also had the long-awaited review of my personal project. I had spent most of last week preparing for it, then had not looked closely at the codebase in roughly two weeks. The review turned out to be a conversation about the challenging parts of the build and the decisions behind it. I knew the project, could explain my thinking, and earned a 100.

That was a much better measure of the work I have been doing than one foggy algorithm performance. It also lines up with my plan after graduation. I am not trying to make algorithm interviews the center of my future. I am continuing to run my business and adding software to what I can offer. I still want the algorithm practice because it makes me a better programmer, but building useful products and explaining the decisions behind them are the skills I expect to use most.

There are fewer than two weeks left, but the ending is not going to be a coast. More algorithm drills, the group project, and another sacrificed holiday weekend are already waiting. Tonight, for the first time in days, I can get a normal amount of sleep.

The linked-list solution works because slow does not have to race fast. It moves one step at a time, and the middle meets it there. That is probably the right approach for this week too.