剑指Offer-链表中环的入口节点

判断链表中是否有环

使用追赶的方法,设定两个指针slowfastslow、fast,均从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fastfast遇到NULLNULL退出。

slowfastslow、fast,均从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fastfast遇到NULLNULL退出。
其中主要的思想就是“环形相遇追及问题”,理解上应该不复杂。

下面的内容转自https://www.cnblogs.com/fankongkong/p/7007869.html

一个链表中包含环,请找出该链表的环的入口结点

方法一、用HashSet来解决

《剑指Offer-链表中环的入口节点》

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 }

《剑指Offer-链表中环的入口节点》

方法二、计算循环

用两个指针,一个fast指针,每次走两步,一个slow指针,每次走一步,当fast指针与slow指针相遇时,假设fast指针走了2x,那么slow指针走了x,由于有环,那么为了便于理解,分为两种情况

情况一:

1、当fast指针仅仅只比slow指针多走一个环,如图所示

《剑指Offer-链表中环的入口节点》

2、第一次相遇的时候,如图

《剑指Offer-链表中环的入口节点》

3、这个时候将fast 重新赋值为开头,如图

《剑指Offer-链表中环的入口节点》

4、再走两次,则找到了环的入口结点

《剑指Offer-链表中环的入口节点》

 

重新梳理一下步骤,解题思路

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指向环的入口。

《剑指Offer-链表中环的入口节点》

 

情况二、当fast比slow 多走n个环

《剑指Offer-链表中环的入口节点》

解题思路

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指向环的入口。

方法二的代码实现

《剑指Offer-链表中环的入口节点》

 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     }

《剑指Offer-链表中环的入口节点》

点赞