如何判断单链表中存在环

2021-01-28  本文已影响0人  追风骚年

关于这个问题,网络上清一色的快慢指针的做法,但是不知道大家有没有思考过,为什么快慢指针可以?快指针一次走两格,慢指针一次走一格,那快指针可以走三格么?

慢指针一格,快指针两格

先看一个链表:


1.png

如果快慢指针路线如下:

步数 慢指针 快指针
1 1
2 3
3 5
4 3
5 5

可见在第步时相遇。
有些人肯定拉皮条,这个环长度是 4 是偶数,如果是奇数的环呢?

2.png

同样看快慢指针:

步数 慢指针 快指针
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
}
上一篇 下一篇

猜你喜欢

热点阅读