1.限制與要求
- 不允許修改鏈表結構。
- 時間復雜度O(n),空間復雜度O(1)。
2.思考
2.1判斷是否有環
如果鏈表有環,那么在遍歷鏈表時則會陷入死循環,利用這個特征,我們可以設計這樣的算法。
- 使用一個slow指針,一個fast指針。
- slow指針一次往后遍歷以1個節點,fast指針一次往后遍歷2個節點,一直做這樣的操作。
- 如果fast指針在遍歷過程中,遍歷到了NULL節點說明鏈表沒有環。
- 否則當slow指針和falst指針相同,則說明環有節點。
2.2環的入口節點
我們假定鏈表頭到環入口的距離是len,環入口到slow和fast交匯點的距離為x,環的長度為R。slow和fast第一次交匯時,設slow走的長度為:d = len + x,而fast走的長度為:2d = len + nR + x,(n >= 1),從而我們可以得知:2len + 2x = len + nR + x,即len = nR - x,(n >= 1),于是我們可以得到這樣的算法。
- 使用一個cur指針指向鏈表頭節點,一個inter指針指向第一次的交匯點。
- cur指針和inter指針一起往后遍歷。
- cur指針和inter指針相等時,cur和inter指針指向的就是環的入口節點。
inter指針在遍歷過程中可能多次(n >= 1)經過環入口節點,但當cur指針第一次達到入口節點時,inter指針此時必然也指向入口節點。
3.代碼實現
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode * detectCycle(ListNode * head) {
if (NULL == head) return NULL;
ListNode * fast = head;
ListNode * slow = head;
while (1)
{
fast = fast->next ? fast->next : NULL;
if (NULL == fast) break;
fast = fast->next ? fast->next : NULL;
if (NULL == fast) break;
slow = slow->next;
if (slow == fast) break;
}
if (NULL == fast) return NULL;
ListNode * cur = head;
ListNode * inter = slow;
while (cur != inter)
{
cur = cur->next;
inter = inter->next;
}
return cur;
}
};