目录
链表中环的入口节点
题目描述
对于一个给定的链表,返回环的入口节点,如果没有环,返回null
拓展:你能给出不利用额外空间的解法么?
方法:快慢指针
一个快指针,两个慢指针。
- 快慢指针同时出发,如果快指针到达null,说明链表没有环
- 如果快慢指针相遇了,说明链表有环。
- 在快慢指针相遇的时候,让第二个慢指针从头结点出发,
- 当两个慢指针相遇的时候,相遇的位置就是环的起点。
原理:
1、假设链表有环,并且环之前的部分长n,环周长m,慢指针速度为1,快指针速度为2。环为顺时针
2、首先快指针和慢指针一起从F0S0出发。
当慢指针经过n的距离到达环的起点S1的时候,快指针走过2n的距离到达F1。
3、快指针此时共走了2n的距离,在环上走了n的距离,
因此快指针此时距离环的起点 n%m 这么多(按顺时针计算)。
也就是说,快针要追上慢针需要多走 m-n%m (即从F1顺时针回到S1的距离)
4、也就是说,当快指针追上慢指针的时候,慢指针从S1走了 m-n%m 到达S2F2。
该点距离环的起点S1有 n%m 这么多距离。(快指针有多少路要追,慢指针就会从起点走多少路)
5、快慢指针在S2F2相遇的时候,另一个慢指针2 从F0S0出发。
慢指针1走到S1要经过 n%m。
慢指针2此时离环起点S1 n-n%m。该距离可以被 m 整除。
因此两个慢指针一定会在S1相遇。
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null) return null;
ListNode slow=head;
ListNode fast=head;
while(slow.next!=null && fast.next!=null && fast.next.next!=null ){
slow=slow.next;
fast=fast.next.next;
if(slow==fast){
ListNode node1=head;
ListNode node2=slow;
while(node1!=node2){
node1=node1.next;
node2=node2.next;
}
return node1;
}
}
return null;
}
}