思路:
- 使用快慢指针遍历链表,定义快慢指针fast,slow,让它们开始都指向头结点。
- 然后判断fast指针是否指向为空以及fast.next指向是否为空。
- 如果非空,则开始遍历。让fast指针一次走两步,slow指针一次走一步。
- 如果单链表有环,那么fast指针会先进入环中,等到slow指针也进入环中时,fast指针就开始在环中追逐slow指针。某一时刻两指针一定会指向同一节点,即说明单链表中有环,返回true。
- 如果fast和fast.next先遍历到了nil,说明没有环,返回false。
代码:
package main
import "fmt"
//定义单链表结点类型
type LNode struct {
Val int
Next *LNode
}
//定义函数判断链表是否有环
func hasCycle(head *LNode) bool {
//定义快慢指针,让它们都指向头结点
slow := head
fast := head
//因fast指针一次走两步,所以首先判断这两步有没有走到nil
for fast != nil && fast.Next != nil {
//既然fast后两步还没指向nil,那么开始循环,slow每次前进一步,fast前进两步。
slow = slow.Next
fast = fast.Next.Next
//fast已经进入环内,slow也进入环内,于是fast开始追赶slow,直到它们指向同一结点,说明有环,返回true。
if fast == slow {
return true
}
}
//fast先指向了nil,说明单链表无环,返回false。
return false
}
func main() {
head := &LNode{} //表示为带头结点的单链表
node1 := &LNode{Val: 1}
node2 := &LNode{Val: 2}
node3 := &LNode{Val: 3}
head.Next = node1
node1.Next = node2
node2.Next = node3
node3.Next = node2 //有环情况
fmt.Println(hasCycle(head))
}
思考:
如果fast指针一次走三步会怎样?走四步呢?