题目地址:142. 环形链表 II - 力扣(LeetCode)
目录
一.解题思路
本题是一道经典的快慢指针应用题。
大体思路如下:
让快指针和慢指针同时出发,快指针在判断链表是否循环同时。当慢指针与快指针相遇,此时再从链表头出发一个慢指针,让两个慢指针同时出发,相遇的点即是链表入环的点。
用数学来推导一下:
假设有一个环形链表,设链表头到入环点距离为L,整个环的长度为O。
首先我们要知道一个基本知识:fast指针永远比slow指针多走一倍的长度,这一点贯穿始终。
当slow走到入环点时,fast距离入环点的距离是x。
但fast比slow实际多走的距离是L的长度。即L = x + n * O 。(n是fast总共走过的圈数,n >= 0)
理解了这点,重点就来了:
此时,fast与slow相距O - x的距离。假设是fast追slow,那么相遇时slow走出的距离也是O - x。
此时,slow与入环点相距x的距离。
这时,从链表头再出发一个慢指针ret,它此时与入环点相距L,即 x + n * O(n >= 0)
假设slow能与ret相遇于入环点,那么需要slow走过x + 整数个圈,即n为整数。
设 x + n * O == x + v (v是slow走完x后剩余距离),解得:v == n * O。
可知,slow能走过整数个圈正好与ret相遇于入环点。
此时,ret/slow所在点即是入环点。
二.代码
还是希望各位能先自主实现一遍。🧐
ListNode *detectCycle(ListNode *head) {
if(head == NULL) return head;
ListNode* slow = head, *fast = head, *ret = head;
while(fast && fast->next != NULL)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
while(ret != slow)
{
ret = ret-> next;
slow = slow-> next;
}
return ret;
}
}
return NULL;
}
三.思考
假如fast指针一次走过的距离是slow指针的3倍甚至更多,还能不能实现这个算法呢?
不一定。
原因:
fast与slow速度差的重要性主要体现在fast追slow的那一段。需要让fast能追到slow。
我们不妨假设环里只有两个点:
就会发现,当fast速度为3,slow为1时,无论如何fast都不可能追上slow!
这是因为假设fast能追上slow。那么相遇时,slow所走的距离设为s,fast所走的距离为3s,相差的2s即是O - x,那么s = (O - x) / 2。倘若O = 2, x = 1,s将不是整数,可是slow不可能走非整数,这与事实冲突。综上,当速度差为其它数时,此算法不一定成立。
看完麻烦三连支持一下博主吧~ 如有错误,敬请斧正