這是我參與8月更文挑戰的第5天,活動詳情查看:8月更文挑戰html
141. 環形鏈表 - 力扣(LeetCode) (leetcode-cn.com)算法
給定一個鏈表,判斷鏈表中是否有環。markdown
若是鏈表中有某個節點,能夠經過連續跟蹤 next
指針再次到達,則鏈表中存在環。 爲了表示給定鏈表中的環,咱們使用整數 pos
來表示鏈表尾鏈接到鏈表中的位置(索引從 0 開始)。 若是 pos
是 -1
,則在該鏈表中沒有環。注意:pos
不做爲參數進行傳遞,僅僅是爲了標識鏈表的實際狀況。app
若是鏈表中存在環,則返回 true
。 不然,返回 false
。ide
進階:oop
你能用 (即,常量)內存解決此問題嗎?post
輸入: head = [3,2,0,-4], pos = 1
輸出: true
解釋: 鏈表中有一個環,其尾部鏈接到第二個節點。
複製代碼
輸入: head = [1,2], pos = 0
輸出: true
解釋: 鏈表中有一個環,其尾部鏈接到第一個節點。
複製代碼
輸入: head = [1], pos = -1
輸出: false
解釋: 鏈表中沒有環。
複製代碼
最容易的就是遍歷鏈表了,循環訪問每一個列表,存入HashSet
,利用HashSet
不可重複的特性,若是咱們添加節點失敗,就說明這個節點以前添加過,天然就是有環的,反之無環。動畫
class Solution {
fun hasCycle(head: ListNode?): Boolean {
val set = mutableSetOf<ListNode>()
var p = head
while (null != p) {
if (!set.add(p)) {
return true
}
p = p.next
}
return false
}
}
複製代碼
要判斷列表中是否有環,能夠定義一個慢指針slow
指向鏈表的頭結點,快指針fast
指向頭結點的下一個結點。而後,慢指針slow
每次向前移動一個位置,快指針fast
每次向前移動兩個位置。這樣,若是鏈表中存在環,快指針就會先進入環,而後追上慢指針。ui
具體思路,可參考此題解中的動畫演示:lua
class Solution {
fun hasCycle(head: ListNode?): Boolean {
if (null == head || null == head?.next) {
return false
}
var slow = head
var fast = head?.next
while (slow != fast) {
if (null == fast || null == fast?.next) {
return false
}
slow = slow?.next
fast = fast?.next?.next
}
return true
}
}
複製代碼
摘自官解:
「Floyd 判圈算法」(又稱龜兔賽跑算法)
假想「烏龜」和「兔子」在鏈表上移動,「兔子」跑得快,「烏龜」跑得慢。當「烏龜」和「兔子」從鏈表上的同一個節點開始移動時,若是該鏈表中沒有環,那麼「兔子」將一直處於「烏龜」的前方;若是該鏈表中有環,那麼「兔子」會先於「烏龜」進入環,而且一直在環內移動。等到「烏龜」進入環時,因爲「兔子」的速度快,它必定會在某個時刻與烏龜相遇,即套了「烏龜」若干圈。
咱們能夠根據上述思路來解決本題。具體地,咱們定義兩個指針,一快一滿。慢指針每次只移動一步,而快指針每次移動兩步。初始時,慢指針在位置 head,而快指針在位置 head.next。這樣一來,若是在移動的過程當中,快指針反過來追上慢指針,就說明該鏈表爲環形鏈表。不然快指針將到達鏈表尾部,該鏈表不爲環形鏈表。
若是咱們知道這個算法的話,那麼要求的進階答案其實就迎刃而解了。
環形鏈表 - 環形鏈表 - 力扣(LeetCode) (leetcode-cn.com)
動畫演示 快慢指針 #141環形鏈表 - 環形鏈表 - 力扣(LeetCode) (leetcode-cn.com)