/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        if (pHead == nullptr || pHead->next == nullptr) {
            return nullptr;
        }
        
        // 步骤1:使用快慢指针判断是否有环
        ListNode *slow = pHead;
        ListNode *fast = pHead;
        
        while (fast != nullptr && fast->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;
            
            // 有环
            if (slow == fast) {
                // 步骤2:找到环的入口
                ListNode *ptr1 = pHead;
                ListNode *ptr2 = slow; // 或者fast,此时它们指向同一个节点
                
                // 两个指针以相同速度前进,相遇点即为环入口
                while (ptr1 != ptr2) {
                    ptr1 = ptr1->next;
                    ptr2 = ptr2->next;
                }
                
                return ptr1; // 环的入口节点
            }
        }
        
        return nullptr; // 无环
    }
};
1.慢指针在走完一圈之前一定会被快指针追上
2.数学原理
设:
链表头到环入口距离为 a
环入口到相遇点距离为 b
相遇点到环入口距离为 c
当快慢指针相遇时:
慢指针走了:a + b
快指针走了:a + b + n(b + c)(n为快指针在环中转的圈数)
由于快指针速度是慢指针的2倍:
2(a + b) = a + b + n(b + c)
化简得:a = (n-1)(b+c) + c
这意味着:从链表头到环入口的距离 = 从相遇点到环入口的距离 + (n-1)圈环长