leetcode系列(5)-- Linked List Cycle II

时间:2021-03-18 19:34:30
Leetcode 142题

题目为: Linked List Cycle II
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Note: Do not modify the linked list.
Follow up:
Can you solve it without using extra space?

解法思想:
主要思想和上一个算法前面基本一样,也是设置一个快指针fp和一个慢指针sp,所不同的是这回是要求出如果链表存在环,那么求出环入口的起始结点。接下来我们就是要从上面的算法中做出一定程度的改变就可以完成题目的要求了。我首先说一下具体的解法,推导过程后面再说。
如果链表中存在环,那么fp和sp一定会相遇,当两个指针相遇的时候,我们设相遇点为c,此时fp和sp都指向了c,接下来令fp继续指向c结点,sp指向链表头结点head,此时最大的不同是fp的步数变成为每次走一步,令fp和sp同时走,每次一步,那么它们再次相遇的时候即为环的入口结点。
接下来我们也许想知道为什么fp和sp指向上面所说的结点之后同时以步数为一走再次相遇的时候一定会指向环的入口结点?

推导:
leetcode系列(5)-- Linked List Cycle II

问题可以转化成求c到d的距离cd为什么等于h到d的距离hd?

首先如图所示,链表的整个长度为L,链表头head为h,假设fp和sp按照箭头所示的方向走。其中环入口点为d,h到d的距离hd为a。fp和sp假设初次相遇在c,初次相遇的时候慢指针sp肯定没有走完整个链表。设d到c的距离dc为x,h到c的距离即为sp初次相遇所走的路程,即设hc长度为s。此外设环的长度为r。而在fp和sp初次相遇在c点的时候,fp则在环内已经走了n圈。由于fp的速度是sp的2倍,接下来我们可以得出:
2s = s + nr        (n>=1)
->    s = nr         (1);
又因为hd距离为a,dc距离为x,hc距离为s,所以可以得出:
 a + x = s            (2);
结合(1)和(2)可以得出:
a + x = nr       ->    
  a + x = (n-1)r + r      ->  
 a + x = (n-1)r + (L-a)        注释:L-a即为环长r
->     a = (n-1)r + (L-a-x)
即L-a-x是相遇点到环的起点的长度,由此可知,从链表头到环起点长度=(n-1)r+(L-a-x),
于是我们从链表头、相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇点为环起点。
所以当fp和sp初次相遇在c点的时候,令fp从c点出发,sp指向
链表头h,两个同时以步数为1同时出发,则再次相遇的时候即为环的入口节点d。


【注意】 为什么快指针一定要设置为慢指针的2倍
看了上面的题解也许你会问问什么快指针一定要设置为慢指针的2倍呢,为什么不是3倍。例如两个人同时从操场出发,其中甲的速度是乙的三倍,当乙跑完一圈的时候,甲跑了三圈,不也是可以相遇的吗。
接下来我会推导,设快指针fp的速度是慢指针速度sp的t倍,其他参数还和上面图片即解释一致。我们可以得出:
ts = s + nr 
->   (t-1)s = nr (3)
由(2)和(3)可以得到:
(t-1)(a+x) = nr
->  (t-1)(a+x) = (n-1)r + r
->  (t-1)(a+x) = (n-1)r + (L-a)
->  a = (n-1)/(t-1)*r + [(L-a)/(t-1) - x]
其中a必定为整数,因为a代表的是h到d的结点个数。所以(n-1)/(t-1)和(L-a)/(t-1) 也须为整数,所以当t为2的时候,一定为整数,当然t也可以为其他,只是遇到链表不一样的情况时候所得到的a不一定为整数。