很多人都說人生就是一個循環,每天重複重複。
而所謂環,對於寫代碼的小夥伴來說是有特殊定義的。我的理解就是節點循環,就成了環。
剛好刷到一個掘金好友分享的騰訊一面算法題:判斷一個單鏈表是不是一個環。
其實有很多辦法來實現,但是我更喜歡用快慢指針來判斷環的形成。思路如下:
- 定義一個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))
}
總結
有時候面試者需要去推測出題人的意圖,條條道路雖然通羅馬,但你的解法不一定能打動考官。