給定一個鏈表,返回鏈表開始入環的第一個節點。 若是鏈表無環,則返回 null。node
爲了表示給定鏈表中的環,咱們使用整數 pos 來表示鏈表尾鏈接到鏈表中的位置(索引從 0 開始)。 若是 pos 是 -1,則在該鏈表中沒有環。bash
說明:不容許修改給定的鏈表。ui
示例 1:spa
輸入:head = [3,2,0,-4], pos = 1
輸出:tail connects to node index 1
解釋:鏈表中有一個環,其尾部鏈接到第二個節點。
複製代碼
示例 2:3d
輸入:head = [1,2], pos = 0
輸出:tail connects to node index 0
解釋:鏈表中有一個環,其尾部鏈接到第一個節點。
複製代碼
示例 3:指針
輸入:head = [1], pos = -1
輸出:no cycle
解釋:鏈表中沒有環。
複製代碼
用兩個指針同時遍歷鏈表,快指針每次走兩步,慢指針每次走一步。若是鏈表中有環,那麼他們終將相遇。可證:自他們相遇後,指針1從起點每次走一步,指針2從相遇點每次走一步,指針1和指針2相遇處就是環的起點。證實以下:code
以下圖,設Y點爲環起點,Z點爲快慢指針相遇點,abc爲這幾個關鍵節點間的路程(可能包括不少節點)。cdn
由於,相遇時快指針走過的路程確定爲慢指針走過的路程的2倍。得:blog
(a+b)2 = a+b+(b+c)n //n>=1,n爲快指針在相遇前繞環的圈數索引
解方程得 a = (b+c)(n-1)+c
因此:
當n=1時,a=c
當n>1時,a=c+n圈
得證。
時間複雜度O(n)
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while( fast != null && fast.next != null ){
slow = slow.next ;
fast = fast.next.next;
if(slow == fast ){
break;
}
}
if( fast == null || fast.next== null ){
return null;
}
while( head != slow ){
head = head.next;
slow = slow.next;
}
return head;
}
}
複製代碼