记录一个有趣的题。
问题:
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
算法描述:
这是很简单有趣的算法:首先用快慢指针来找是否存在环;接着如果有环,就是一个小小的数学变化:首先快指针的步长是慢指针的两倍,且两指针相遇一定在环内。设首结点到入环的第一个结点的距离为a
,在快慢指针停在环内的结点距离入环第一个结点为b
,在环内剩余长度为c
,则有如下表达式:快指针步长 = 2 * 慢指针步长
=> a + b + c + b = 2 * (a + b)
,解得:c = a
。那么设p = head
,则p
只要再走和slow或者fast
一样的步长,当他们相遇时,那个结点就是入环的第一个结点(画图好理解)。
代码:
type ListNode struct {
Val int
Next *ListNode
}
func detectCycle(head *ListNode) *ListNode {
fast := head
slow := head
hasCycle := false
// 快慢指针找环
for fast != nil && fast.Next != nil {
fast = fast.Next.Next
slow = slow.Next
if fast == slow {
hasCycle = true
break
}
}
if hasCycle {
p := head
for p != slow {
p = p.Next
slow = slow.Next
}
return p
}
return nil
}