给定一个头结点为 head 的非空单链表,返回链表的中间结点。
    如果有两个中间结点,则返回第二个中间结点。

    常规方法也是先遍历链表计算 n,再遍历一次得到第 n / 2 个节点,也就是中间节点。

    1. public ListNode middleNode(ListNode head) {
    2. int n = 0;
    3. ListNode cur = head;
    4. while (cur != null) {
    5. ++n;
    6. cur = cur.next;
    7. }
    8. int k = 0;
    9. cur = head;
    10. while (k < n / 2) {
    11. ++k;
    12. cur = cur.next;
    13. }
    14. return cur;
    15. }

    如果想一次遍历就得到中间节点,需要使用「快慢指针」的技巧:
    让两个指针 slow 和 fast 分别指向链表头结点 head。
    每当慢指针 slow 前进一步,快指针 fast 就前进两步,这样,当 fast 走到链表末尾时,slow 就指向了链表中点。

    当链表的结点数量是偶数时:
    image.png
    当 fast 指针走到 null 时,slow 走到了中间靠右的结点

    当链表的结点数量是奇数时:
    image.png
    当 fast 指针走到的结点的下一个结点是 null 时,slow 走到了中间的结点

    1. public ListNode middleNode(ListNode head) {
    2. // 快慢指针都指向头结点
    3. ListNode fast = head;
    4. ListNode slow = head;
    5. // 快指针走到末尾时停止
    6. while(fast != null && fast.next != null) {
    7. // 慢指针走一步,快指针走两步
    8. slow = slow.next;
    9. fast = fast.next.next;
    10. }
    11. // 慢指针指向中点
    12. return slow;
    13. }