class Solution {
  public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        if (pHead == nullptr) return nullptr;
        ListNode* fast = pHead;
        ListNode* slow = pHead;
        while (fast && fast->next) {
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow) break;
        }
        if (fast == nullptr || fast->next == nullptr) return nullptr;
        slow = pHead;
        while (fast != slow) {
            fast = fast->next;
            slow = slow->next;
        }
        return slow;
    }
};

Fast walks faster, so when Slow and Fast first met, it was inside the loop.

Slow then went back to the beginning to walk the walk again, while Fast slows down and continues looping inside.

The second time they meet, it'll be right at the entrance of the loop.