带环链表问题的进阶版,不仅要判断是否存在环,还要找出环回的位置。题面如下:
这道题在原本快慢指针的基础上加入了更多的操作细节,简而言之,快慢指针的相遇与否可以说明链表中是否存在环路(这在另一篇博客中已经记录过),但是这并不能直接反映出相交的位置,这里面涉及到一个简单的数学推导:官方题解中给出了完整的推导
总而言之,这个推出的结论就是本题的解题关键,也是难点:
当Slow和Fast指针相遇时,我们再使用一个指针从链表头部与Slow指针一齐向后运动,最终两者一定会交汇在链表的环回处。
这个结论在理解原理的基础上可以记下,下面准备给出源代码。
和之前一样,我写了专门的两个函数来负责指针的移动:oneStepForward和twoStepForward,也就是负责将指针向前移动一个和两个位置,代码如下:
/*move the pointer one position forward*/
bool oneStepForward(ListNode*& Ptr)
{
if(Ptr && Ptr->next)
{
Ptr = Ptr->next;
return true;
}
else
return false;
}
/*move the pointer two positions forward*/
bool twoStepForward(ListNode*& Ptr)
{
if(oneStepForward(Ptr) && oneStepForward(Ptr))
return true;
else
return false;
}
随后移动指针,确定是否有环存在(必须要确定是否存在环路):
/*slow-fast pointers algorithm*/
while(true)
{
/*move the two pointers*/
if(oneStepForward(SlowPtr) && twoStepForward(FastPtr))
{
/*the 2 pointers meet, jump out of the loop*/
if(SlowPtr == FastPtr)
break;
}
/*no cycle in the list*/
else
return nullptr;
}
最后根据上述的结论,既然已经找到了快慢指针的交汇点,就使用一个从链表头部开始的指针(这里是Result),同步的和慢指针SlowPtr一步步的移动,直至它们相遇,这个交点就是环回点,且一定存在,找到后返回即可。
/*get the intersection node*/
while(Result != SlowPtr)
{
Result = Result->next;
SlowPtr = SlowPtr->next;
}
return Result;