问题来源:环形链表 II
问题描述:
题目给定信息:题目中要求我们从给定链表中如果这个链表有环的话返回环的开始节点,如果没环的话返回null
问题分析:
这道题依然是求给定链表是否有环的变异题,要求我们求出有环链表的环的开始节点,在链表求环的问题中我们详细介绍了使用Set方法实现,这里不再过多的叙述。
我们来详细的介绍一下使用快慢指针的方法找到有换链表中环的开始节点。使用快慢指针能比较简单的判断是这个链表时候有换,但难点在于如何利用快慢指针找到环的开始节点。
通过这样的数学分析我们能够看得出来,想同时间内快指针走的路程是慢指针路程的两倍,那么从快慢指针相遇的节点开始,head和meet相遇的节点就是环的开始节点。
函数实现:
第一种方法:
1 public ListNode detectCycle(ListNode head) { 2 //定义两个指针,快指针每一次走一步,慢指针每一次走两步 3 ListNode fast = head; 4 ListNode slow = head; 5 //meet表示如果有环时两指针相遇的地点 6 ListNode meet = null; 7 // 找到快慢指针相遇的位置并且保存到meet变量中,此时已经能够证明链表是有换的 8 while (fast != null) { 9 //每一次快指针先走一步,慢指针也走一步 10 fast = fast.next; 11 slow = slow.next; 12 //如果快指针为空,证明走到了链表的结尾处,该链表没有环 13 if (fast == null) { 14 return null; 15 } 16 fast = fast.next; 17 //当两个指针相遇时候,保存下相遇节点的位置 18 if (fast == slow) { 19 meet = fast; 20 break; 21 } 22 } 23 if(meet==null){ 24 return null; 25 } 26 while(head!=null){ 27 if(head==meet){ 28 return head; 29 } 30 head=head.next; 31 meet=meet.next; 32 } 33 return null; 34 }
第二种方法:
1 public ListNode hasCycle(ListNode head) { 2 Set<ListNode> set=new HashSet<ListNode>(); 3 while(head!=null){ 4 if(set.contains(head)){ 5 return head; 6 }else{ 7 set.add(head); 8 head=head.next; 9 } 10 } 11 return null; 12 }
运行结果(按照第一种方法的代码执行):