用2个辅助指针,第一个指针p1每次走一步,第二个指针p2每次走两步。当p1走到环的起点时走了a步,那么p2肯定在环中,而且走了2a步,距离环的起点是2a-a步。如果p1再走b步与p2相遇,那么就会有这么一个等式
a + b = 2 * (a + b) - k * n
其中,k就是b在环中走的圈数,n是环的长度。因为相遇时可能p2在环中走了k圈了.上述等式可以转换为下式
a + b = k * n
这时,把p1拉回链表起点,p2留在相遇点。p1和p2每次都走一步,那么当p1走了a步后,也就是环的起点时,p2也走了a步,但是因为p2已经在环的b位置,那么再走a步后,根据上面的公式,就会发现p2走到了环的起点。因为p1也在环的起点,所以2个指针就会相遇,而相遇点就是环的起点。
代码如下:
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *p1 = head, ListNode *p2 = head;
do {
if ((p2 == 0) || (p2->next == 0))
return 0;
p2 = p2->next->next;
p1 = p1->next;
} while (p1 != p2);
//把p1拉回起点
for (p1 = head; p1 != p2; p1 = p1->next, p2 = p2->next);
return p1;