package main

func EntryNodeOfLoop(pHead *ListNode) *ListNode{
	slow, fast := pHead, pHead

	for fast != nil && fast.Next != nil {
		slow = slow.Next
		fast = fast.Next.Next

		if slow == fast {
			index1, index2 := pHead, slow
			for index1 != index2 {
				index1 = index1.Next
				index2 = index2.Next
			}

			return index1
		}
	}

	return nil
}

同样使用快慢指针的思路,如果链表中有环,快慢指针一定相遇(快指针每次走两步,慢指针每次走一步,根据物理学上的相对运动,相当于慢指针不动,快指针每次移动一个位置去追赶慢指针,一定可以追得上)

假设两者相遇时,慢指针在非环部分(环入口节点 3 之前的部分)走了距离 x,在环中走的距离为 y;

快指针在非环部分走的也是 x,而在环的部分走了 y + n(y+z) 的距离,其中 y + z 是环的长度,n 表示在相遇之前快指针走的圈数;

快指针每次走两步,所以可以得到这个公式:x+y+n(y+z) = 2(x+y)

移项化简:

x+y+y+z+(n-1)(y+z) = 2x + 2y

x = z + (n-1)(y+z)

y+z 是环的长度,无论快指针绕了多少圈,真正起到相遇作用的还是 z

x = z 这说明两者相遇时,慢指针走过的非环部分,和快指针距离环入口处的距离是一致的

那么我们只需要求出相遇点,然后使用两个指针,一个从相遇点出发,一个从头节点出发,这两个节点相遇的节点就是入口地点了。