问题描述如下:
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Follow up:
Can you solve it without using extra space?
从问题来看,如果可以充分利用额外空间的话,这个题目是不难的,然而题目提出了一个要求,能否在不使用任何额外空间的情况下解决这个问题。
通过反复思考,我觉得这题类似于追击问题,可以用一个快速遍历指针和一个慢速遍历指针对这个链表进行遍历,如果存在环,那么这个快速指针肯定会在环中某一处追到这个慢指针。尽管有这样的想法,但是在判断出了是否有环之后,该如何进一步获取环的起点呢?个人能力有限,之前没有做过类似的题目,本着学习的目的,于是我查阅了资料,在LeetCode的讨论区里得到了解答:
设立一个慢指针slow,一个快指针fast,慢指针每次走一步,快指针每次走两步。假设从head到环起点start的距离为x,环的长度为y(即从起点走回起点所需要走的步数)。
我们知道,当存在环的时候,fast和slow必然会在环中某一处相遇,假设相遇点距离start为m,于是slow和fast在m处相遇时,slow走了:x+ky+m,fast走了:x+ty+m。因为fast走的为slow的两倍,于是:
ty可以被y整除,所以x+m+2ky应当也能被y整除,即(x+m) mod y=0。于是,可以推断,当二者在m出相遇时,再绕环走x步,便一定可以到达环的起点。
可得出代码如下:
class Solution { public: ListNode *detectCycle(ListNode *head) { if(!head) return NULL; ListNode* slow = head; ListNode* fast = head; do{ if(!fast) return NULL; slow = slow->next; fast = fast->next; if(fast) fast = fast->next; else return NULL; }while( slow != fast ); slow = head; while( slow != fast ){ slow = slow->next; fast = fast->next; } return slow; } };