思路:若是開始有兩個指針指向頭結點,一個走的快,一個走的慢,若是有環的話,最終通過若干步,快的指針總會超過慢的指針一圈從而相遇。oop
如何計算環的長度呢?能夠第一次相遇時開始計數,第二次相遇時中止計數。spa
如何判斷環的入口點?碰撞點p到鏈接點的距離=頭指針到鏈接點的距離,所以,分別從碰撞點、頭指針開始走,相遇的那個點就是鏈接點。指針
當fast與slow相遇時,show確定沒有走完鏈表,而fast已經在還裏走了n(n>= 1)圈。假設slow走了s步,那麼fast走了2s步。fast的步數還等於s走的加上環裏轉的n圈,因此code
有:2s = s + nr。所以,s = nr。 blog
設整個鏈表長爲L,入口據相遇點X,起點到入口的距離爲a。由於slow指針並無走完一圈,因此:a + x = s,帶入第一步的結果,有:a + x = ast
nr = (n-1)r + r = (n-1)r + L - a;即:a = (n-1)r + L -a -x;class
這說明:從頭結點到入口的距離,等於轉了(n-1)圈之後,相遇點到入口的距離。所以,咱們能夠在鏈表頭、相遇點各設一個指針,每次各走一步,兩個指針一定相遇,且相遇第一點爲環入口點。List
判斷是否有環循環
bool hasCycle(ListNode *head) { ListNode *fast(head), *slow(head); while(fast && fast->next) { fast = fast->next->next; slow = slow->next; if(fast == slow) return true; } return false; }
計算環的長度鏈表
int loopLength(ListNode *head) { if(hasCycle(head) == false) return 0; ListNode *fast = head; ListNode *slow = head; int length = 0; bool begin = false; bool again = false; while( fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; //超兩圈後中止計數,挑出循環 if(fast == slow && again== true) break; //超一圈後開始計數 if(fast == slow && again == false) { begin = true; again= true; } //計數 if(begin == true) ++length; } return length; }
//求環的入口結點
ListNode* findLoopEntrance(ListNode *head) { ListNode *fast = head; ListNode * slow = head; while( fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; //若是有環,則fast會超過slow一圈 if(fast == slow) { break; } } if(fast == NULL || fast->next == NULL) return NULL; slow = head; while(slow != fast) { slow = slow->next; fast = fast->next; } return slow; }