关于这个问题,网络上清一色的快慢指针的做法,但是不知道大家有没有思考过,为什么快慢指针可以?快指针一次走两格,慢指针一次走一格,那快指针可以走三格么?
慢指针一格,快指针两格
先看一个链表:
1.png
如果快慢指针路线如下:
步数 | 慢指针 | 快指针 |
---|---|---|
一 | 1 | 1 |
二 | 2 | 3 |
三 | 3 | 5 |
四 | 4 | 3 |
五 | 5 | 5 |
可见在第五
步时相遇。
有些人肯定拉皮条,这个环长度是 4 是偶数,如果是奇数的环呢?
同样看快慢指针:
步数 | 慢指针 | 快指针 |
---|---|---|
一 | 1 | 1 |
二 | 2 | 3 |
三 | 3 | 5 |
四 | 4 | 7 |
五 | 5 | 4 |
六 | 6 | 6 |
在第步,快慢指针还是相遇。
慢指针一格,快指针三格
偶数环
1.png步数 | 慢指针 | 快指针 |
---|---|---|
一 | 1 | 1 |
二 | 2 | 4 |
三 | 3 | 3 |
第三步相遇。
奇数环
2.png步数 | 慢指针 | 快指针 |
---|---|---|
一 | 1 | 1 |
二 | 2 | 4 |
三 | 3 | 7 |
四 | 4 | 5 |
五 | 5 | 3 |
六 | 6 | 6 |
这里依然会相遇。
小结
快慢指针查找环路问题看似非常简单,其实内部是一个数学问题,假如两个指针一个每次一格,一个每次两格。因为快指针相对于慢指针是每次多一步,所以快指针先进入环内旋转,慢指针后加入内,所以环中可以看作快指针在追赶慢指针,还是因为快指针相对于慢指针的速度是多一步,所以每次移动都会缩小他们之间的一格距离。又由于环的长度是有穷的,最终的距离为0,刚刚好就追上了。
并且在第一次相遇的时候,快指针比慢指针刚好多走了环长度的整数倍。
type ListNode struct {
Val int
Next *ListNode
}
func hasCycle(head *ListNode) bool {
fast, slow := head, head
for fast != nil && slow != nil {
if slow.Next != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next
} else {
return false // 遇到空节点则无环
}
if fast.Next != nil {
fast = fast.Next
} else {
return false // 遇到空节点则无环
}
if slow == fast {
return true // 相遇则有环
}
}
return false
}
网友评论