一个链表中包含环,请找出该链表的环的入口结点
方法一、用HashSet来解决
1 public ListNode EntryNodeOfLoop(ListNode pHead){ 2 HashSet<ListNode> hs = new HashSet<ListNode>(); 3 while(pHead!=null){ 4 if(!hs.add(pHead))//如果包含了,那么这个就是入口结点 5 return pHead; 6 pHead = pHead.next; 7 } 8 return null; 9 }
方法二、计算循环
用两个指针,一个fast指针,每次走两步,一个slow指针,每次走一步,当fast指针与slow指针相遇时,假设fast指针走了2x,那么slow指针走了x,由于有环,那么为了便于理解,分为两种情况
情况一:
1、当fast指针仅仅只比slow指针多走一个环,如图所示
2、第一次相遇的时候,如图
3、这个时候将fast 重新赋值为开头,如图
4、再走两次,则找到了环的入口结点
重新梳理一下步骤,解题思路
a、第一步,找环中相汇点。分别用fast,slow指向链表头部,slow每次走一步,fast每次走二步,直到fast==slow找到在环中的相汇点。
b、第二步,找环的入口。接上步,当fast==slow时,fast所经过节点数为2x,slow所经过节点数为x,设环中有n个节点,fast比slow多走一圈有2x=n+x; n=x;
可以看出slow实际走了一个环的步数,再让fast指向链表头部,slow位置不变。
假设链表开头到环接口的距离是y,如下图所示,那么x-y表示slow指针走过的除链表开头y在环中走过的距离,那么slow再走y步,此时fast结点与slow结点相遇,fast == slow ,x-y+y=x = n,即此时slow指向环的入口。
情况二、当fast比slow 多走n个环
解题思路
a、第一步,找环中相汇点。分别用fast,slow指向链表头部,slow每次走一步,fast每次走二步,直到fast==slow找到在环中的相汇点。
b、第二步,找环的入口。接上步,当fast==slow时,fast所经过节点数为2x,slow所经过节点数为x,设环中有n个节点,fast比slow多走r圈有2x=rn+x; x=rn;(r为圈数,n为一圈的结点数)
可以看出slow实际走了多个环的步数,再让fast指向链表头部,slow位置不变。
假设链表开头到环接口的距离是y,那么x-y表示slow指针走过的除链表开头y在环中走过的距离,那么slow再走y步,此时fast结点与slow结点相遇,fast == slow ,x-y+y=x = rn,即此时slow指向环的入口。
方法二的代码实现
1 public ListNode EntryNodeOfLoop2(ListNode pHead){ 2 ListNode fast = pHead; 3 ListNode slow = pHead; 4 while(fast != null && fast.next != null){ 5 fast = fast.next.next; 6 slow = slow.next; 7 //当快指针 与 慢指针相遇时 8 if(fast == slow){ 9 fast = pHead; 10 //再次相遇 11 while(fast != slow){ 12 fast = fast.next; 13 slow = slow.next; 14 } 15 return fast; 16 } 17 } 18 return null; 19 }