前言
环形链表II-力扣
本题主要考察了对环形链表的掌握,逻辑思维和一些基本的数学能力。
思路
一个环形链表大致可以看成这样
首先,我们该怎么判断此链表是环形呢?
我们先来看看这道题:环形链表-力扣
这道题让我们判断链表是否成环。可以使用快慢指针的方式,慢指针走一步,快指针走两步,当快指针与慢指针相遇时,则说明链表成环。
这种思路该怎么解释呢?
假设当slow指针走到环的入口时,fast指针与slow指针的距离为N。那么此时fast与slow指针每走一次,彼此的距离减一,最后为0。
bool hasCycle(struct ListNode *head) {
struct ListNode* slow=head;
struct ListNode* fast=head;
while(fast&&fast->next){
slow=slow->next;//慢指针走一步
fast=fast->next->next;//快指针走两步
if(slow==fast)//相遇时说明成环
return true;
}
return false;
}
我们再回到环形链表II这道题。我们想要找到环的入口,可以用头指针与慢指针相遇的方法。原理是这样的,我们先设前缀路程为L,环的路程为C。当fast与slow相遇时,slow指针走过的路程为:L+N ,fast指针走过的路程为:L+x
∗
*
∗C+N(x为绕环走过的圈数)。因为fast的路程等于slow指针的两倍,所以可以得出整式:2
∗
*
∗(L+N)=L+x
∗
*
∗C+N。化简得:L=x
∗
*
∗C-N。如图所示,此时slow与入口的距离为:C-N,所以如果此时头指针与slow指针同时出发,无论slow走几圈,都必定会再入口相遇。
代码
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow=head;
struct ListNode* fast=head;
while(fast&&fast->next){
slow=slow->next;
fast=fast->next->next;
if(fast==slow){
struct ListNode* meet=slow;
while(meet!=head){
meet=meet->next;
head=head->next;
}
return meet;
}
}
return NULL;
}