import java.util.*;
//方法一:哈希法
//方法二:双指针法

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead) {
        //方法一:哈希法,通过遍历链表,将链表中的节点保存在哈希集合中,在把节点保存到集合之前,需要检验集合中是否已经存在。
        //如果存在,则表示链表存在环,且第一个重复的节点就是环的入口节点;如果不存在,则将该节点保存到集合中。
//         //特殊值处理,空链表
//         if(pHead == null){
//             return null;
//         }
        
//         HashSet<ListNode> hashSet = new HashSet<>();//创建一个对象HashSet
//         ListNode head = pHead;
//         //循环遍历,直到遇到第一个相同的节点,即为链表中环的入口节点
//         while(head != null){
//             //判断集合中是否存在当前节点
//             if(hashSet.contains(head)){//集合中存在当前节点
// //                 return head;
//                 break;
//             }else{//集合中不存在当前节点
//                 hashSet.add(head);
//                 head = head.next;
//             }
//         }
        
//         return head;
        
        //方法二:双指针法,定义两个指针,分别是快指针和慢指针
        //特殊值处理,空链表
        if(pHead == null){
            return null;
        }
        
        ListNode fast = pHead;
        ListNode slow = pHead;
        //通过循环遍历,找到相遇的节点C(如果链表中存在环)
        while(fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                break;
            }
        }
        //退出循环时如果fast或者fast.next为空,则不存在环
        if(fast == null || fast.next==null){
            return null;
        }
        
        fast = pHead;//链表中存在环,更新快指针为头指针,
        //快指针与慢指针以相同的速度从头指针处遍历链表,慢指针在相遇节点C处遍历链表,再次相遇时的节点即为链表中的环的入口节点。
        while(fast != slow){
            fast = fast.next;
            slow = slow.next;
        }
        
        return fast;
    }
}