环形链表Ⅱ
这一篇我们来讲解如何返回环形链表的入环节点环形链表Ⅱ
同样这里我们也需要两个快慢指针的存在
这里我们设头节点到环形入口的距离为L,环形的周长为C,入环口到快慢指针相遇的距离为N
(这里我们说到两个指针一定会相遇,具体请看环形链表,文章结尾有链接)
我们这里先给出一个结论:
从头结点到入环口的距离等于入环口到fast=slow这个节点的距离
为什么会有这样的结论呢?下面我们来证明一下:
slow指针走的距离:L+N;
fast指针走的距离:L+XC+N(这里慢指针只要进入环形,fast就一定会走一圈甚至更多,所以这里设置一个未知数X)
这里我们利用fast指针的速度是slow指针的二倍,所以我们得到一下等式
2(L+N)=L+XC+N
化简一下得到
L=X*C - N
这里我们就需要结合数学思维来思考一下
最简单的情况就是我们这里X取1
得到L=C-N
对吗,同学们这里可以清晰的看到fast=slow这个节点到入环口和头节点到入环口的距离是相等的
那么又有同学问了X如果不取1,我们这个结论还相等吗
答案是当然相等,我们这里在梳理一下思路
L=X*C - N这个式子我们是不是还可以将他改变一下形式
L=(X-1)*C+C-N
这个式子就更加清晰了,X不管再大,这里我们最后绕完圈圈,最后都需要加上一个(C-N)。
当
这里我们在定义一个head指针指向头节点和meet指针指向fast=slow的节点,L=(X-1)*C+C-N,这里我们结合这个式子看图,meet和head节点同时移动,这里我们可以看出head指针L距离走完meet不管在这个环形中绕了多少圈都会最终都是在入环口相遇。
接下来代码实现
struct ListNode { //题目中的链表结构
int val;
struct ListNode *next;
};
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* fast=head,*slow=head; //这里我们依然定义快慢指针
while(fast && fast->next)
{
slow=slow->next;
fast=fast->next->next; //跟环形链表Ⅰ这个题目相同
if(slow==fast) //到这里我们找到了两个指针在环形中相遇的节点
{
struct ListNode* meet = fast;
while(meet!=head)
{ //定义meet和head指针同时移动
meet=meet->next;
head=head->next;
}
return meet; //当两个指针相遇说明遇到入环口的节点
}
}
return NULL; //走到这里说明没有环形结构
}
题目到这里就写完了,如果有对链表不熟悉的同学可以看一下巨可爱熊写的关于链表的讲解
链表讲解
这里是环形链表Ⅰ的讲解环形链表Ⅰ