給定一個鏈表,判斷鏈表中是否有環。
如果鏈表中有某個節點,可以通過連續跟蹤 next 指針再次到達,則鏈表中存在環。 為了表示給定鏈表中的環,我們使用整數pos
來表示鏈表尾連接到鏈表中的位置(索引從 0 開始)。 如果pos
是 -1,則在該鏈表中沒有環。
注意:pos
不作為參數進行傳遞,僅僅是為了標識鏈表的實際情況。
如果鏈表中存在環,則返回true。否則,返回false。
要求:
使用快慢指針的方法判斷給定鏈表是否有環,時間復雜度應為 O(N),空間復雜度應為 O(1)。
代碼實現需要定義快慢指針,快指針一次走兩步,慢指針一次走一步,如果快慢指針相遇則說明有環,實現這一算法。
示例:
輸入:head = [3,2,0,-4], pos = 1
輸出:true
解釋:鏈表中有一個環,其尾部連接到第二個節點。
答案:
public class ListNode {
public var data: Int
public var next: ListNode?
public init(_ data: Int) {
self.data = data
self.next = nil
}
}
func hasCycle(_ head: ListNode?) -> Bool {
var slow: ListNode? = head
var fast: ListNode? = head
while fast != nil && fast?.next != nil {
slow = slow?.next
fast = fast?.next?.next
if slow === fast {
return true
}
}
return false
}
let node1 = ListNode(1)
let node2 = ListNode(2)
let node3 = ListNode(3)
let node4 = ListNode(4)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node2 //創建環,pos=1
let head = node1
print(hasCycle(head)) //true
知識點詳解:
鏈表:鏈表是一種常見和重要的數據結構,主要有一下幾點需要理解:
- 鏈表由一系列節點(Node)組成,每個節點包含數據域data和指針域next。
- 數據域用于存儲節點的數據,指針域用于指向下一個節點。
- 鏈表中的節點使用指針連成一串,每個節點指針都指向下一個節點,這樣就構成了鏈表。
- 鏈表有一個頭節點
head
,作為鏈表的入口,頭節點不存儲數據。(鏈表也可以沒有頭節點)
(單)鏈表.png
pos:表示鏈表尾部連接到鏈表中的位置(索引從0開始)。也就是說,如果鏈表中有環,pos就表示環的入口節點的索引。例如:pos默認-1,表示沒有環,如果再第一個節點上有環那么pos就是0,pos=1那么第二個節點就是環的入口,pos=2環的入口在第三個節點上,以此類推...pos不會作為輸入參數傳入函數,僅僅表示了鏈表是否有環以及環的入口在鏈表中的位置。實際上,我們不需要知道pos
的具體值,只需要通過快慢指針判斷鏈表是否存在環即可。
===:三個等號操作符表示指針比較,判斷兩個指針是否指向同一個節點。
算法思路
- 定義快慢兩個指針fast和slow,初始化都指向頭節點head。
- 每次快指針fast向前移動兩步,慢指針slow向前移動一步。
- 檢查快慢指針是否相遇,如果
fast === slow
,則說明鏈表有環。 - 如果快指針遇到null,說明鏈表無環。
時間復雜度分析:
0.快指針走的速度是慢指針的兩倍
1.在環外的時候慢指針在后,快指針在前,不可能重合
2.在環內,快指針走幾步追上了慢指針。
3.快指針到末尾還沒相遇,說明無環。
結論:時間復雜度O(N)。
空間復雜度
該算法僅使用了兩個額外的指針:快指針fast
和慢指針slow
,空間消耗都是常數級的,不隨鏈表長度N
增加而改變。空間復雜度是O(1)。
BTW
這道題的題目分析、要求和示例與題目無關,??
感謝各位簡友的寶貴時間與意見!文章難免有疏漏或錯誤,如有涉及不當之處,還望能夠提出寶貴意見。感激不盡!