概述
目的是在一个给定的链表中找出循环的起始节点。如果链接列表中的最后一个节点指向前面的另一个节点,那么链接列表中就存在一个循环。
例子

上面的链表有一个循环。循环的起始节点是节点 2。以下是我们可以遵循的方法
-
首先,检测给定的链表是否有一个周期。有两个指针。一个是慢速指针,另一个是快速指针。这两个指针最初都指向头部节点
-
现在将慢指针移动1个节点,将快指针移动2个节点。
slow := slow.Next
fast := fast.Next.Next
-
如果慢指针和快指针在任何时间点上都是一样的,那么这个链表就有细胞。
-
快指针和慢指针只能在循环中的一个节点上相遇。让我们假设他们在节点3相遇。现在得到循环的长度。其长度为3
-
然后在节点的头部保持一个指针,另一个指针与它保持周期长度的距离。因此,一个指针将被加在节点1处,另一个指针将在节点4处。
-
移动这两个指针,直到它们是相同的。它们将在周期开始的节点(即节点2)相遇。
程序
以下是相同的程序。
package main
import "fmt"
func main() {
first := initList()
ele4 := first.AddFront(4)
first.AddFront(3)
ele2 := first.AddFront(2)
first.AddFront(1)
//Create cycle
ele4.Next = ele2
output := cycleStartNode(first.Head)
fmt.Println(output.Val)
}
type ListNode struct {
Val int
Next *ListNode
}
type SingleList struct {
Len int
Head *ListNode
}
func (s *SingleList) AddFront(num int) *ListNode {
ele := &ListNode{
Val: num,
}
if s.Head == nil {
s.Head = ele
} else {
ele.Next = s.Head
s.Head = ele
}
s.Len++
return ele
}
func initList() *SingleList {
return &SingleList{}
}
func cycleStartNode(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return nil
}
slow := head
fast := head
cycleExists := false
for slow != nil && fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
if slow == fast {
cycleExists = true
break
}
}
if !cycleExists {
return nil
}
cycleNode := slow
curr := cycleNode
lengthCycle := 1
for curr.Next != cycleNode {
lengthCycle++
curr = curr.Next
}
curr = head
for i := 0; i < lengthCycle; i++ {
curr = curr.Next
}
for head != curr {
head = head.Next
curr = curr.Next
}
return head
}
输出
2