法一:藉助輔助空間
代碼:
class Solution:
def hasCycle(self, head: ListNode) -> bool:
a = set()
while head:
if head in a:
return True
a.add(head)
head = head.next
return False
理解: 用一個set數據結構存儲每個節點地址;
時間複雜度O(n*1):訪問每個節點O(n)+存儲每個節點O(1);
空間複雜度O(n)
法二: 快慢指針法
代碼:
class Solution:
def hasCycle(self, head: ListNode) -> bool:
slow = fast = head
# if not head: # 沒必要這樣寫可以加入while循環判斷更簡潔
# return False
while fast and fast.next: # 防止head爲空和出現空指針的next的情況
slow = slow.next
fast = fast.next.next
if slow is fast:
return True
return False
理解:
思路:定義一個快指針和慢指針,每次快指針走2步,慢指針走1步,判斷快指針是否與慢指針重逢
時間複雜度O(n):
情況一:鏈表部分成環O(n);
部分成環時,快指針先於慢指針進入環,慢指針進環時間O(n);當快慢指針都進入環,假設環節點數量爲K,當快慢指針第一次相遇時,快指針至少已經在環內已經比慢指針多走一圈(多走的這一圈是當慢指針進入後開始算的),時間O(k); 綜上,時間複雜度O(k+n),即爲O(n)
情況二:鏈表完全成環O(n)
同起點,第一次相遇時,快指針已經在環內已經比慢指針多走一圈;時間複雜度O(n)
空間複雜度O(1)
法三:遞歸標記法
代碼:
class Solution:
def hasCycle(self, head: ListNode) -> bool:
if not head:
return False
if head == 0xcafebabe:
return True
head.val = 0xcafebabe
return self.hasCycle(head.next)
理解:
思路:把訪問過的值都進行賦值,如果鏈表完全成環,則必會出現重複值;0xcafebabe=3405691582;至於爲啥用這個我目前沒有查到爲什麼?
時間複雜度:O(n);訪問O(n)+賦值O(1)
空間複雜度:O(1)
參考:
https://leetcode-cn.com/problems/linked-list-cycle/solution/huan-xing-lian-biao-by-leetcode/