最优解:快慢指针
public ListNode middleNode(ListNode head){
if(head==null){//链表为空
return null;
}
if(head.next==null){//只有一个节点
return head;
}
ListNode fast=head;
ListNode slow=head;//快慢指针在同一节点
while (fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next;
}
return slow;
}
快慢指针(也称为龟兔赛跑算法)来找到链表的中间节点,是一种非常高效且简洁的算法思想。这种算法的核心在于利用两个指针以不同的速度遍历链表,从而在一次遍历中就能找到中间节点。
算法思想
- 初始化:
- 创建两个指针,
slow
和fast
,都指向链表的头节点head
。
- 创建两个指针,
- 遍历链表:
- 在遍历链表的过程中,
slow
指针每次向前移动一步(即slow = slow.next
),而fast
指针每次向前移动两步(即fast = fast.next.next
)。 - 由于
fast
指针的速度是slow
指针的两倍,因此当fast
指针到达链表末尾时(即fast
或fast.next
为null
),slow
指针将位于链表的中间位置(或对于偶数长度的链表,位于两个中间节点中的第二个)。
- 在遍历链表的过程中,
- 处理边界情况:
- 如果链表为空(
head == null
),则直接返回null
,因为没有中间节点。 - 如果链表只有一个节点(
head.next == null
),则该节点就是中间节点,直接返回head
。
- 如果链表为空(
- 返回结果:
- 当
fast
指针到达链表末尾时,循环结束。此时,slow
指针所指向的节点就是链表的中间节点(或偶数长度链表中的第二个中间节点)。
- 当
优点
- 时间复杂度:O(n),其中 n 是链表的长度。因为只需要遍历链表一次。
- 空间复杂度:O(1)。只使用了两个额外的指针,不随链表长度的增加而增加。
应用场景
- 找到链表的中间节点。
- 在一些需要分割链表的问题中,如“将链表从中间节点断开”。
- 在某些递归或迭代算法中,需要确定链表的中点以优化性能或简化逻辑。
示例
假设链表为 1 -> 2 -> 3 -> 4 -> 5
,则:
slow
和fast
初始时都指向节点1
。- 第一次循环后,
slow
指向2
,fast
指向3
。 - 第二次循环后,
slow
指向3
,fast
指向5
。 - 第三次循环时,
fast
尝试指向5.next
,但发现5.next
为null
,因此循环结束。 - 此时,
slow
指向3
,即链表的中间节点(对于奇数长度的链表)。
对于偶数长度的链表,如 1 -> 2 -> 3 -> 4
,算法会返回第二个中间节点(即 3
),但同样可以根据需要调整算法以返回第一个中间节点。