微信扫一扫打赏支持

php实现找链表中环的入口节点(画图、看评论)

php实现找链表中环的入口节点(画图、看评论

一、总结

画图、看评论

 

 

二、php实现找链表中环的入口节点

题目描述:

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

 

 

三、代码

 

  • 第一步,找环中相汇点。分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相汇点。
  • 第二步,找环的入口。接上步,当p1==p2时,p2所经过节点数为2x,p1所经过节点数为x,设环中有n个节点,p2比p1多走一圈有2x=n+x; n=x;可以看出p1实际走了一个环的步数,再让p2指向链表头部,p1位置不变,p1,p2每次走一步直到p1==p2; 此时p1指向环的入口。

不严谨,如果环比较小,在慢针没入环的时候,快针可能已经转了N久了 



设起点到相遇点距离为x,起点到入口点距离为y,环长度为r,则快慢针相遇时,满足2x-x=nr,n为快针在环中转的圈数。--> x=nr
快慢针相遇点距环入口点距离x-y
相遇后,快针从起点重新开始以步长为1速度开始走,经过距离y到达环入口点,慢针走y步后距离环入口点距离为x-y+y=x=nr,即走到了环入口点,两个指针相遇

 

代码没有问题,但是数学证明不严谨



我来说明一下多走k圈和1圈其实是一样的:根据题目要求,找入口结点就相当于找倒数第n个结点,而倒数第kn个结点其实就是倒数第n个结点。所以这个题就变成找倒数第kn个结点,刚好p1已经走了kn个结点,再让p2指向链表头部,p1位置不变,p1,p2每次走一步直到p1==p2; 此时p1指向环的入口。
这就说明不管是1圈还是k圈,结果是一样的,可以直接看成一圈来解答。

 



多走k圈和多走一圈是一样的,a是头结点到入口结点的距离,b是入口节点Y到相遇处Z的距离,c是环的长度减去b。
相遇时有:
S_{fast} = 2S_{slow}
假设相遇时pFast在环内转了k圈,则
a + k(b+c) + b = 2(a + b) 
移项得:
a = (k-1)(b+c) + c
说明头结点X到入口结点Y的距离等于从相遇处Z开始在环内转悠k-1圈(k >= 1)后,最后从Z到Y的距离。当k =1时候,a = c,此时pFast比pSlow多走一圈(也就是大家一直讨论的情况)

 

 

 1 public class Solution {
 2  
 3     ListNode EntryNodeOfLoop(ListNode pHead){
 4         if(pHead == null || pHead.next == null)
 5             return null;
 6         ListNode p1 = pHead;
 7         ListNode p2 = pHead;
 8         while(p2 != null && p2.next != null ){
 9             p1 = p1.next;
10             p2 = p2.next.next;
11             if(p1 == p2){
12                 p2 = pHead;
13                 while(p1 != p2){
14                     p1 = p1.next;
15                     p2 = p2.next;
16                 }
17                 if(p1 == p2)
18                     return p1;
19             }
20         }
21         return null;
22     }
23 }

 

posted @ 2018-05-23 22:40  范仁义  阅读(293)  评论(0编辑  收藏  举报