题目地址:
https://leetcode.com/problems/linked-list-cycle-ii/
链表求环,如果有环,返回环的入口,否则返回null。经典快慢指针算法。先用快慢指针判断有没有环,见https://blog.csdn.net/qq_46105170/article/details/104013645,然后重新设一个节点cur等于head,接着cur和slow同时出发,每轮循环走一步,直到相遇。则相遇点即为环的入口。代码如下:
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null) {
return null;
}
ListNode slow = head, fast = head;
do {
slow = slow.next;
fast = fast.next.next;
} while (fast != null && fast.next != null && slow != fast);
// 说明无环
if (slow != fast) {
return null;
}
ListNode cur = head;
while (cur != slow) {
cur = cur.next;
slow = slow.next;
}
return cur;
}
}
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
时间复杂度 。
算法正确性证明:
设链表有环,链表的nodes是这样排列:
也就是说从
到
形成一个环,环的边数为
。我们对于slow和fast各自走了多少步做分析。当slow走到
时,它走了
步,而fast走的步数是slow的两倍,所以fast走了
步,fast所处于的位置的下标是
。设slow再走
步就与fast相遇,那么有同余式:
所以
也就是说slow再走
步就到达了
,而新的节点cur从head出发同时走
步正好也会走到
,所以相遇点就是环的入口。