方法一
难想,但代码容易实现
根据第一道环形链表的题目我们可以得知快慢指针相交的节点,但是如果想要知道进入环形链表的第一个节点,我们就还需要定义一个指针从链表的头节点开始,与相交的节点同时行走,当两个节点重合时重合的那个节点就是环形链表的第一个节点。那么原理是怎样的呢?我们可以定义头节点到进入环形链表的第一个节点的长度为L,进入环形链表的第一个节点到相遇的节点长度为N,整个环形链表的长度为C。则快指针fast走的路程为L+x*C+N,慢指针slow走的路程为L+N,因为快指针走的路程为慢指针走的路程的二倍,所以我们可以得出等式2(L+N)=L+x*C+N,整理后可得L=x*C-N---->L=(x-1)*C+C-N。由此可知两指针相遇的位置距离进入环形链表第一个节点的长度与头节点距离进入环形链表第一个节点的长度相等。所以我们可以来实现一下这个想法。
typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head)
{ListNode*slow=head;ListNode*fast=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;if(fast==slow){ListNode*meet=slow;while(meet!=head){meet=meet->next;head=head->next;}return meet;}}return NULL;
}
方法二
好想,但代码不容易实现
如果第一种方法不容易想出,那么我们可以应用之前做过的相交链表的思想来实现方法二。当我们找到相遇的节点时,可以将该节点的下一个节点设为新的头节点,再将相遇的节点的next指针置为NULL。这样操作,我们就可以将含头节点的链表与新头节点的链表视为相交链表,然后应用相交链表的思想找出进入环形链表的第一个节点。那么我们现在开始实现一下这个思想。
typedef struct ListNode ListNode;ListNode*Find(ListNode*headA,ListNode*headB)
{ListNode*pcurA=headA;ListNode*pcurB=headB;int lenA=0;int lenB=0;while(pcurA){pcurA=pcurA->next;++lenA;}while(pcurB){pcurB=pcurB->next;++lenB;}int gap=abs(lenA-lenB);ListNode*longList=headA;ListNode*shortList=headB;if(lenA<lenB){longList=headB;shortList=headA;}while(gap--){longList=longList->next;}while(longList!=shortList){longList=longList->next;shortList=shortList->next;}return shortList;}struct ListNode *detectCycle(struct ListNode *head)
{ListNode*slow=head;ListNode*fast=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;if(slow==fast){ListNode*meet=slow;ListNode*newhead=meet->next;meet->next=NULL;return Find(newhead,head);}}return NULL;
}
大家感兴趣的可以自行尝试哦~
. - 力扣(LeetCode)