← 返回题目列表

如何找到单链表的中间节点?

高频 简单 第 4 / 28 题 更新于 2026/07/28
链表快慢指针

简化版

快慢指针一次遍历搞定:慢指针一次走 1 步、快指针一次走 2 步。快指针走到末尾时,慢指针正好在中间。时间 O(n)、空间 O(1),只遍历一遍,不用先数长度再走一半。

详细版

ListNode middleNode(ListNode head) {
    ListNode slow = head, fast = head;
    while (fast != null && fast.next != null) {
        slow = slow.next;       // 走 1 步
        fast = fast.next.next;  // 走 2 步
    }
    return slow;
}

快指针速度是慢指针的两倍,当快指针到终点时,慢指针刚好走了一半,停在中间。

偶数个节点时有两个「中间」(比如 4 个节点的第 2、3 个),返回哪个取决于循环条件:

  • 条件 fast != null && fast.next != null:偶数时返回靠后的中间节点(第 n/2+1 个)。
  • 条件 fast.next != null && fast.next.next != null:偶数时返回靠前的中间节点。

面试要问清楚要哪个,或主动说明你的写法返回的是哪一个。

完整版教学

一、为什么快慢指针能定位中点

设链表长 n。慢走 1、快走 2,两者步数始终是 2:1。快指针走完全程 n 步,慢指针只走了 n/2 步——正好中点。这比「先遍历一遍数出长度 n,再从头走 n/2 步」少走一趟,一次遍历就够。

二、奇偶情况分别验证

  • 奇数(如 1 2 3 4 5):中点唯一是 3。快指针停在最后一个节点 5fast.next == null),慢指针在 3。✅
  • 偶数(如 1 2 3 4):两个中间是 23。用 fast != null && fast.next != null 时,快指针会走到 null,慢指针停在 3(靠后那个)。想要 2(靠前),把循环条件改成看 fast.nextfast.next.next

三、和「判环」共用一套模板

快慢指针是链表里的万能模板:判环、找中点、找倒数第 k 个、回文链表判断,都是它的变体。区别只是快慢指针的速度差终止条件。所以把这套「一次遍历定位」的思路吃透,一大类链表题都能套。

四、典型用途

  • 归并排序链表:先用快慢指针找中点拆两半,再递归归并。
  • 判断回文链表:找到中点,反转后半段,再和前半段逐个比对。

这两道进阶题都以「找中点」为第一步,所以它不只是道基础题,更是很多题的地基。

五、返回前中还是后中

链表长度模板循环条件返回位置
奇数 1→2→3→4→5常规模板fast != null && fast.next != null3
偶数 1→2→3→4后中点fast != null && fast.next != null3
偶数 1→2→3→4前中点fast.next != null && fast.next.next != null2

用数字走一遍偶数长度 1→2→3→4:如果 slow=1, fast=1,每轮 slow 走 1 步、fast 走 2 步;第一轮后 slow=2, fast=3,第二轮后 slow=3, fast=null,所以返回后中点 3。这不是错,只是模板选择决定的结果。

面试写找中点前最好主动说一句:我这个循环条件在偶数长度时返回后中点;如果要前中点,终止条件要改。

六、常见误区与追问

  • 误区:偶数长度链表只有一个中点。 偶数长度天然有前中点和后中点,题目如果没说明,要主动说明你的返回策略。
  • 误区:快慢指针一定比两次遍历复杂。 代码不长,但能一趟完成,尤其适合作为回文链表、链表排序的子步骤。
  • 误区:循环条件随便写都一样。 fast != null && fast.next != nullfast.next != null && fast.next.next != null 在偶数长度时结果不同。
  • 追问:为什么快到尾时慢在中间? 快速指针速度是慢指针两倍,快走完整条链时慢只走了一半。
  • 追问:空链表怎么办? 若题目可能传空链表,应先判断 head == null;很多 LeetCode 中点题会保证非空。
  • 追问:找中点在归并排序中为什么重要? 它能把链表尽量均分成两半,保证递归深度接近 log n

七、加强记忆

找中点用快慢指针「快 2 慢 1,快到头、慢到中」,一次遍历、O(1) 空间。偶数个节点时返回前中还是后中,由循环条件决定,写之前先问清楚要哪个。