题目描述

✅ 876. 链表的中间结点

image-20260928215303090

image-20260928215303091

题意分析

返回链表的中间节点;长度为偶数时,中间有两个节点,要求返回后一个。若从 $0$ 开始编号,长度为 n 的链表要返回的下标就是 $\lfloor n/2 \rfloor$。

返回值是原链表中的节点引用,节点仍然连接后面的部分,不需要新建节点或截断链表。链表不能按下标直接访问,可以利用两个指针的速度差,在遍历过程中找到这个位置。

解法:快慢指针

核心思路

[!blue]

令 slow 和 fast 都从头节点出发,每轮让 slow 走一步、fast 走两步。完成 k 轮后,slow 走了 k 步,fast 走了 2k 步。因此用快指针判断何时到达链表末尾,就能让慢指针停在约一半的位置。

循环条件是 fast 和 fast.next 都非空:此时可以安全读取 fast.next.next,它允许为空。退出时分两种情况:

  • 长度为 $2m + 1$:执行 m 轮后,fast 位于最后一个节点,因其后继为空而停止;slow 位于下标 m,正是唯一中点。
  • 长度为 $2m$:执行 m 轮后,fast 恰好走到链表末尾之后,变为空;slow 位于下标 m,正是两个中点中的后一个。

两种情况都让慢指针停在 $\lfloor n/2 \rfloor$,所以退出后直接返回 slow,不需要预先计算长度或单独处理奇偶。只有一个节点时,循环一次也不执行,返回头节点即可。

解题步骤

  • 初始化 slow = head、fast = head。
  • 先判断 fast 非空,再判断它的后继非空;两者都满足时,slow 前进一步,fast 前进两步。
  • 循环结束后返回 slow 指向的节点。

代码实现

class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;

        // 先判空再读后继,快慢同起点让偶数长度停在第二个中点。
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }

        return slow;
    }
}
func middleNode(head *ListNode) *ListNode {
    slow := head
    fast := head
    // 先判空再读后继,快慢同起点让偶数长度停在第二个中点。
    for fast != nil && fast.Next != nil {
        slow = slow.Next
        fast = fast.Next.Next
    }
    return slow
}

复杂度分析

  • 时间复杂度:$O(n)$,循环执行 $\lfloor n/2 \rfloor$ 轮,每轮只移动固定次数的指针。
  • 空间复杂度:$O(1)$,只使用两个指针。

关键点总结

[!green]

  • 完成 k 轮后,慢指针前进 k 步、快指针前进 2k 步,速度差决定了中点位置。
  • 两个指针都从 head 出发,配合当前循环条件,偶数长度时自然返回第二个中点。
  • 条件判断利用短路求值,必须先检查 fast,再访问 fast.next。

易错点总结

[!yellow]

  • 只判断 fast.next != null:偶数长度时 fast 会变成空,下一轮访问 next 发生空指针错误。
  • 把条件写成 fast.next != null && fast != null:判断顺序错误,短路求值无法保护空指针。
  • 将 fast 初始化为 head.next:在相同循环条件下,偶数长度时会少执行一轮,返回前一个中点。
  • fast 每轮只走一步:两个指针同速,slow 最终不会停在中点。
  • 返回 slow.val:题目要求的是节点引用,而不是节点值。
  • 修改 slow.next:题目只要求定位节点,不能为了返回中点而切断原链表。

相似题目

题目 难度 关联与区别
2095. 删除链表的中间节点 中等 原题删掉中点,需要让慢指针停在中点前驱,本题只返回中点本身。
143. 重排链表 中等 找中点是拆分链表的基础,原题之后反转后半段再交错连接。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2024/67928740
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!