注意:请务必看完以下技术内容再来做这道题【LeetCode例141】【c语言】环形链表-CSDN博客
1 题目介绍
给定一个链表,返回链表开始入环的第一个节点。 从链表的头节点开始沿着
next
指针进入环的第一个节点为环的入口节点。如果链表无环,则返回null
。为了表示给定链表中的环,我们使用整数
pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果pos
是-1
,则在该链表中没有环。注意,pos
仅仅是用于标识环的情况,并不会作为参数传递到函数中。说明:不允许修改给定的链表。
示例1:
输入以下链表,值为3的节点为head节点
返回值应该为值为2的节点
示例2:
输入以下链表,值为1的节点为head节点
返回值应该为值为1的节点
示例3:
输入以下链表,值为1的节点为head节点
返回值应该为NULL
照例放上题目链接: . - 力扣(LeetCode)
2 解题思路
我们首先先判断这个链表是否带环,这里就不多赘述了,如果不太清楚的话可以看文章开头链接的内容
判断完链表是否带环之后我们就可以得到重合在一起的 fast slow 指针
不难看出,此时fast或者slow到入口节点的距离与head到入口节点的距离相等!
那么我们只要在此时同时遍历slow和head,让其重合就能找到入口节点!
3 实现代码
typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head)
{
if(head == NULL || head->next == NULL)
{
return NULL;
}
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
{
ListNode* meet = head;
for(meet = head; meet != slow; meet = meet->next, slow = slow->next)
;
return meet;
}
}
return NULL;
}
4 关于本题的思考
事实上,本体如何解并不是我们关注的重点,我们关注的重点应该是为什么本题可以这么解,以至于我们得讨论一个数学问题
·我们设 head 到入口的距离为L,slow / fast 到入口的距离为M, 整个环的周长为C
·那么除开M的距离,一个环剩下的距离应该是C-M
·因为我们不知道 fast 在环里面走了几圈才遇到 slow ,所以我们再设 fast 走的圈数为 k(在以下这个例子里,fast 走了两圈不到,完整的圈只有1,所以 k 为 1)
我们都直到 fast 的速度时 slow 的两倍,所以 fast 走过的路程一定是 slow 的两倍
因此我们可以得到公式
2 * (L + C - M) = L + k * C + (C - M)
左边是2 * slow 走的距离 = 右边是 fast 走的距离
带入k并化简可得: L = M
即得证,fast或者slow到入口节点的距离与head到入口节点的距离相等