题目大意:141题目的扩展,给出单链表,判断是否有环,如果有环,找出环的开始的结点,如果没有环,返回null。
法一(借鉴):在已经找出单链表环的基础上再找开始结点,要时刻记住这个环不一定是从尾结点到头结点,有可能是中间的某一段。所以对于这里具体路径的分析,有两个博客可看http://blog.csdn.net/xy010902100449/article/details/48995255,http://blog.csdn.net/willduan1/article/details/50938210,都是从数学层面去证明方法的可行性,也就是为什么可以在找到相遇点后,再从头开始遍历,第二次相遇点就是开始结点的问题。代码如下(耗时1ms):
1 public ListNode detectCycle(ListNode head) { 2 ListNode fast = head; 3 ListNode slow = head; 4 while(fast != null && fast.next != null) { 5 fast = fast.next.next; 6 slow = slow.next; 7 if(fast == slow) { 8 fast = head; 9 while(fast != slow) { 10 fast = fast.next; 11 slow = slow.next; 12 } 13 return fast; 14 } 15 } 16 return null; 17 }
法二:利用了141的法二,直接用set存入,如果有相同的则说明肯定是环的开始结点,直接返回即可。此方法的时间复杂度和空间复杂度都挺大的。代码如下(耗时16ms):
1 Set<ListNode> list = new HashSet<>(); 2 while(head != null) { 3 if(list.contains(head)) { 4 return head; 5 } 6 else { 7 list.add(head); 8 head = head.next; 9 } 10 } 11 return null;