很多人都說人生就是一個迴圈,每天重複重複。
而所謂環,對於寫程式碼的小夥伴來說是有特殊定義的。我的理解就是節點迴圈,就成了環。
剛好刷到一個掘金好友分享的騰訊一面演算法題:判斷一個單連結串列是不是一個環。
其實有很多辦法來實現,但是我更喜歡用快慢指標來判斷環的形成。思路如下:
- 定義一個slow指標,指向單連結串列的頭部節點head。定義一個fast指標,初始化為head.next。
2.然後先判斷fast和fast.next是否是空,如果為空,肯定不是環。
3.然後開始移動快慢兩個指標。slow指標每次只移動一個節點,fast指標每次移動2個節點。
4.如果在移動的過程中slow指向的節點等於fast指向的節點,那麼說明迴圈了,這是一個環。
5.如果移動到連結串列最後(假設不是環,有尾部)還是沒有slow和fast節點重合,那麼說明不是環。
所謂環,那麼就一定會快慢指標一定會相遇。
那麼用golang實現一下:
package main
import (
"fmt"
)
type ListNode struct {
Val int
Next *ListNode
}
func HasCircle(head *ListNode) bool {
slow, fast := head, head.Next
if fast == nil || fast.Next == nil {
return false
}
for fast != nil && fast.Next != nil {
if slow == fast {
return true
}
slow = slow.Next
fast = fast.Next.Next
}
return false
}
func main() {
// create the list
head := &ListNode{Val: 1}
head.Next = &ListNode{Val: 2}
head.Next.Next = &ListNode{Val: 3}
head.Next.Next.Next = &ListNode{Val: 4}
head.Next.Next.Next = head.Next
fmt.Println("Is circle? ", HasCircle(head))
}
死去的記憶又在攻擊我了,我想起多年前去一家網際網路醫療公司面試的時候也遇到這道題,我也給出了這個解法,但是面試官一臉懵逼,無法理解我的思路。今天我仔細想想,也許是他想看到我用深度優先搜尋(DFS)來實現。
所謂深度優先,就是一種遞迴演算法,用於搜尋圖或樹資料結構的所有頂點。該演算法從起始節點開始,儘可能沿著每條路徑探索,直到無法再前進為止,然後進行回溯。DFS通常使用堆疊來跟蹤已發現的節點,以便進行回溯。這種演算法的時間複雜度為O(V+E),其中V是頂點數,E是邊數。在實際應用中,DFS還有許多應用,包括尋找連通分量、檢測圖中的環、拓撲排序等。
檢測環,用它就對啦,實現如下所示:
···
func dfs(node ListNode, visited map[ListNode]bool) bool {
if node == nil {
return false
}
if visited[node] {
return true
}
visited[node] = true
return dfs(node.Next, visited)
}
func HasCircleByDFS(head ListNode) bool {
visited := make(map[ListNode]bool)
return dfs(head, visited)
}
func main() {
// create the list
head := &ListNode{Val: 1}
head.Next = &ListNode{Val: 2}
head.Next.Next = &ListNode{Val: 3}
head.Next.Next.Next = &ListNode{Val: 4}
head.Next.Next.Next = head.Next
fmt.Println("Is circle? ", HasCircleByDFS(head))
}
···
總結
有時候面試者需要去推測出題人的意圖,條條道路雖然通羅馬,但你的解法不一定能打動考官。