前言
在一天dp,一天链表,一天贪心的被轮的过程中,发现了道这么个好玩意儿题,感觉这款题目特别经典,然后不仅考察了数据结构的链表的基本还考察了拓展的环形链表以及令我闻风丧胆的math成分在,于是本着费曼学习法的思维,于是想着将其输出成一个简单易懂的题解来分享一下。
题目
链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
大致是这么个事,给一串链表,先判断是不是环形链表,如果不是就返回空指针,如果是,那就继续深入判断找出环形链表的第一个结点。
思路:
是否是环形链表?
首先思考如何判断是否是环形链表。因为如果不是环形链表的话,会沿着链表走到空指针。反之,会在链表环里反复循环,所以我们可以用同向的尺取法,设两个指针变量slow,fast,令它们一个一次走一步一个一次走两步,并以快的那个地址以及其next为判定条件是否为空。这样如果fast走到了空或fast->next为空则非环形链表。如果是环形链表的话,fast会花费<=slow的时间进入环内,且当slow也进入环内后,fast能以一步多走slow一步的速度套圈追赶slow,最终能追到slow,也就是说当slow==fast时该链表为环形链表。
找到环形链表第一个结点
然后我们设slow刚刚进入环内时,需要走b的距离才能接触到fast,然后环形链表长度减去b的长度设为c,环形链表外的长度设为a。
则fast抓到slow时fast跑了n圈,(fast到达第一个环形链表结点时重置)此时fast跑的距离为
n*(b+c)+b+a=(n+1)b+a+n*c;因为fast跑的距离总是slow的两倍,则(n+1)b+a+c=2(a+b);
得到a=c+(n−1)(b+c),所以从fast遇见slow的那个点到环形链表第一个结点的距离c加上(n-1)圈的环形链表长度b+c后的长度恰好等于a,也就是现在从相遇点一次走一步一直走,然后同时从外部链表第一个结点一次走一步一直走,会恰好相遇在环形链表的第一个结点。
代码实现
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
struct ListNode*slow=head,*fast=head;int a=0;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(fast==slow)
{
a=1;
break;
}
}
while(a)
{
if(slow==head)
return head;
slow=slow->next;
head=head->next;
}
return NULL;
}
};
完结撒花