目录
判断环形链表
141. 环形链表 - 力扣(LeetCode) (leetcode-cn.com)
我们判断的结果无外乎两种情况----是环形链表或不是环形链表。
因此如果有个指针指向了NULL,那么就证明了这不是个环形链表。但是如果要是环形链表,那么指针就会在环中一直寻找NULL,因此程序就会陷入死循环,这里就需要用快慢指针(详见上篇文章)来解决这个问题。
slow=slow->next;
fast=fast->next->next;
这里我们可以理解为fast与slow两人正在跑步,当slow跑一步时,fast跑两步。当slow在进环后,fast一定能在一圈内追上slow,这是因为在追击过程中,他们之间的距离每次缩短1,他们之间的相对距离最多是1圈,这样slow最多走一圈,fast最多走两圈。这样在一个环形跑道中的fast总会与slow相遇的,而当fast与slow相遇时就能证明这是一个环形链表了。
bool hasCycle(struct ListNode *head) {
struct ListNode *fast=head;
struct ListNode *slow=head;
while(fast&&fast->next)//如果没有环的话,fast肯定会比slow先遇到null
{
slow=slow->next;
fast=fast->next->next;
if(fast==slow)
{
return true;
}
}
return false;
}
寻找入环节点
在寻找节点之前我们要知道一个公式L=(N-1)*C+(C-X).
在上文中我们可以知道,只要快指针和慢指针相遇了,就表示这个链表带环,而且我们可以知道相遇的点meet,在上图中就是4。 此时slow走的路程就是L+X,fast所走的路程就是L+N*C+X (N>=1,N表示在slow进环之前fast在环内转了N圈)。
因为快指针所走的距离是慢指针的二倍,因此我们能得出一个等式2*(L+X)=L+N*C+X,由这个等式可以推导出 L=N*C-X,即L=(N-1)*C+(C-X)。这时我们再建立一个head指针从头开始走,当走了C-X步后,meet正好走到入环节点的位置,head剩下的路程就是N*C了(N>=0),因此meet与head相遇的点就是入环的节点。
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode *fast=head;
struct ListNode *slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(slow==fast)
{
struct ListNode *meet=slow;
while(meet!=head)
{
head=head->next;
meet=meet->next;
}
return meet;
}
}
return NULL;
}