55 链表中环的入口结点
题目要求:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
思路一: Floyd环判定算法
使用fastptr和sloeptr两个速度不相同的指针,一旦它们两个进入链表中的环,就肯定会相遇
时间复杂度O(n)
空间复杂度O(1)
错误代码:没有看清楚题目啊?不是让你判断链表是否有环,而是要让你找到环的入口节点啊
1 public class Solution { 2 public ListNode EntryNodeOfLoop(ListNode pHead){ 3 //考虑特殊情况 4 if(pHead == null || pHead.next==null|| pHead.next.next==null) return null; 5 //定义两个pointer 6 ListNode fastptr = pHead;//快指针走两步 7 ListNode slowptr = pHead;//慢指针走一步 8 while( fastptr.next.next!=null && slowptr.next!=null){ 9 fastptr = fastptr.next.next; 10 slowptr = slowptr.next; 11 if(fastptr == slowptr) return fastptr; 12 } 13 return null; 14 } 15 }
正确代码:
25行的break语句,一定要放进if的{}中去,否则无法通过
1 /* 2 public class ListNode { 3 int val; 4 ListNode next = null; 5 6 ListNode(int val) { 7 this.val = val; 8 } 9 } 10 */ 11 public class Solution { 12 public ListNode EntryNodeOfLoop(ListNode pHead){ 13 //考虑特殊情况 14 if(pHead == null || pHead.next==null|| pHead.next.next==null) return null; 15 //定义两个pointer,和环是否存在的真假 16 ListNode fastptr = pHead;//快指针走两步 17 ListNode slowptr = pHead;//慢指针走一步 18 boolean isExist = false; 19 //判断环是否存在 20 while( fastptr.next.next!=null && slowptr.next!=null){ 21 fastptr = fastptr.next.next; 22 slowptr = slowptr.next; 23 if(fastptr == slowptr){ 24 isExist = true; 25 break; 26 } 27 } 28 if(isExist == true){//环存在,找到环的入口节点 29 slowptr = pHead; //只初始化其中一个指针,另外一个指针不动 30 while(slowptr!= fastptr){ 31 fastptr = fastptr.next; //每个指针各走一步 32 slowptr = slowptr.next; //每个指针各走一步 33 } 34 return slowptr; 35 } 36 return null; //环不存在,返回null 37 } 38 }
思路二:利用HashMap
这个方法完全不用分成 判断环存在+找到入口 两个步骤
遍历整个链表,如果节点在hashmap中已经存在,那么它肯定就是环的入口啊
时间复杂度O(n)
空间复杂度O(n)
1 import java.util.HashMap; 2 public class Solution { 3 public ListNode EntryNodeOfLoop(ListNode pHead) 4 { 5 HashMap<Integer,Integer> hs=new HashMap<>(); 6 while(pHead!=null){ 7 if(!hs.containsKey(pHead.val)){ 8 hs.put(pHead.val,1); 9 }else{ 10 return pHead; 11 } 12 pHead=pHead.next; 13 } 14 return null; 15 } 16 }
思路一的证明
链接:https://www.nowcoder.com/questionTerminal/253d2c59ec3e4bc68da16833f79a38e4
来源:牛客网
两个结论: 
  1、设置快慢指针,假如有环,他们最后一定相遇。  
  2、两个指针分别从链表头和相遇点继续出发,每次走一步,最后一定相遇与环入口。
 
  证明1:设置快慢指针fast和low,fast每次走两步,low每次走一步。假如有环,两者一定会相遇(因为low一旦进环,可看作fast在后面追赶low的过程,每次两者都接近一步,最后一定能追上)。 
   证明2:
 
  设: 
  链表头到环入口长度为--a  
  环入口到相遇点长度为--b  
  相遇点到环入口长度为--c
 
则:相遇时
  快指针路程=a+(b+c)k+b ,k>=1  其中b+c为环的长度,k为绕环的圈数(k>=1,即最少一圈,不能是0圈,不然和慢指针走的一样长,矛盾)。 
   慢指针路程=a+b  
  快指针走的路程是慢指针的两倍,所以: //这一步我不太明白,作为备注
   (a+b)*2=a+(b+c)k+b  
  化简可得: 
  a=(k-1)(b+c)+c  这个式子的意思是:  链表头到环入口的距离=相遇点到环入口的距离+(k-1)圈环长度。其中k>=1,所以k-1>=0圈。所以两个指针分别从链表头和相遇点出发,最后一定相遇于环入口。
            
 
作者:shareidea            
 
出处:https://www.cnblogs.com/shareidea94/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。   
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号