给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
输入描述:输入分为2段,第一段是入环前的链表部分,第二段是链表环的部分,后台将这2个会组装成一个有环或者无环单链表
返回值描述:返回链表的环的入口结点即可
解题思路:
方法1:hash法,记录第一次重复的结点
通过使用set或者map来存储已经遍历过的结点,当第一次出现重复的结点时,即为入口结点。
public ListNode EntryNodeOfLoop(ListNode head) {
/*
Set<ListNode> set = new HashSet<>();
while(head != null){
if(set.contains(head))
return head;
set.add(head);
head = head.next;
}
return null;
}
方法2:快慢指针
通过定义slow和fast指针,slow每走一步,fast走两步,若是有环,则一定会在环的某个结点处相遇(slow == fast),根据下图分析计算,可知从相遇处到入口结点的距离与头结点与入口结点的距离相同(C-B的距离与A-B的距离相同)。因此需要把快指针fast冲向指向头结点A,此时慢节点在相遇节点C,快慢节点再以相同的速度(快:A-B,走距离X,慢:C-B距离X)移动,走到入口节点B相遇
public ListNode EntryNodeOfLoop(ListNode head) {
if(head == null)
return null;
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(slow == fast)
break;///记录快慢指针第一次相遇的节点。链表有环
}
if(fast == null || fast.next == null)
return null;//快指针指向空节点代表无环
fast = head;//快指针重新指向头结点,此时慢节点还在第一次相遇的节点C
while(fast != slow){
slow = slow.next;//C-B,C代表快慢指针第一次相遇的节点,
fast = fast.next;//A-B,A代表头结点,B,代表环的入口节点,快慢指针以相同的速度遍历,直
//到两者再次在环的入口节点B相遇
}
return slow;
}