目錄
-
- 方法一:利用空間
- 方法二:快慢指針
方法一:利用空間
周遊連結清單,對于每個節點對象,新增屬性isVisited = true。同時每次周遊判斷下一個節點是否擁有isVisited屬性,如果有那麼下一個節點就是入環的第一個節點。
- 時間複雜度O(n)
- 空間複雜度O(n)
var hasCycle = function(head) {
var curr = head;
while(curr != null) {
if(curr.next == null) {
return false;
}
if(curr.next.isCheck) {
return curr.next;
} else {
curr.isCheck = true;
curr = curr.next;
}
}
return false;
};
方法二:快慢指針
用兩個指針同時周遊連結清單,快指針每次走兩步,慢指針每次走一步。如果連結清單中有環,那麼他們終将相遇。可證:自他們相遇後,指針1從起點每次走一步,指針2從相遇點每次走一步,指針1和指針2相遇處就是環的起點。證明如下:
如下圖,設Y點為環起點,Z點為快慢指針相遇點,abc為這幾個關鍵節點間的路程(可能包括很多節點)。
因為,相遇時快指針走過的路程肯定為慢指針走過的路程的2倍。得:
(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)
- 空間複雜度O(1)
var hasCycle = function(head) {
var p1 = head;
var p2 = head;
while(p2 !== null && p2.next !== null) {
p1 = p1.next;
p2 = p2.next.next;
if(p1 === p2) { //判斷有環
p1 = head; //p1從頭開始每次走一步,p2從相遇處開始每次走一步
while(p1 != p2) {
p1 = p1.next;
p2 = p2.next;
}
return p1;
}
}
return false;
};