leetcode 142. 环形链表 II golang实现

描述
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
思路

原作者地址

当fast == slow时, 两指针在环中 第一次相遇 。下面分析此时fast 与 slow走过的 步数关系 :

设链表共有 a+ba+b 个节点,其中 链表头部到链表入口 有 aa 个节点(不计链表入口节点), 链表环 有 bb 个节点(这里需要注意,aa 和 bb 是未知数,例如图解上链表 a=4a=4 , b=5b=5);设两指针分别走了 ff,ss 步,则有:
fast 走的步数是slow步数的 22 倍,即 f = 2sf=2s;(解析: fast 每轮走 22 步)
fast 比 slow多走了 nn 个环的长度,即 f = s + nbf=s+nb;( 解析: 双指针都走过 aa 步,然后在环内绕圈直到重合,重合时 fast 比 slow 多走 环的长度整数倍 );
以上两式相减得:f = 2nbf=2nb,s = nbs=nb,即fast和slow 指针分别走了 2n2n,nn 个 环的周长 (注意: nn 是未知数,不同链表的情况不同)。


如果让指针从链表头部一直向前走并统计步数k,那么所有 走到链表入口节点时的步数 是:k=a+nb(先走 aa 步到入口节点,之后每绕 11 圈环( bb 步)都会再次到入口节点)。
而目前,slow 指针走过的步数为 nbnb 步。因此,我们只要想办法让 slow 再走 aa 步停下来,就可以到环的入口。
但是我们不知道 aa 的值,该怎么办?依然是使用双指针法。我们构建一个指针,此指针需要有以下性质:此指针和slow 一起向前走 a 步后,两者在入口节点重合。那么从哪里走到入口节点需要 aa 步?答案是链表头部head。

如果让指针从链表头部一直向前走并统计步数k,那么所有 走到链表入口节点时的步数 是:k=a+nb(先走 aa 步到入口节点,之后每绕 11 圈环( bb 步)都会再次到入口节点)。
而目前,slow 指针走过的步数为 nbnb 步。因此,我们只要想办法让 slow 再走 aa 步停下来,就可以到环的入口。
但是我们不知道 aa 的值,该怎么办?依然是使用双指针法。我们构建一个指针,此指针需要有以下性质:此指针和slow 一起向前走 a 步后,两者在入口节点重合。那么从哪里走到入口节点需要 aa 步?答案是链表头部head。
实现
func DetectCycle(head *ListNode) *ListNode {
	slow := head
	fast := head

	for {
		if fast == nil || fast.Next == nil{
			return nil
		}
		slow = slow.Next
		fast = fast.Next.Next
		if fast == slow{
			break
		}
	}
	cur := head
	for cur != slow{
		cur = cur.Next
		slow = slow.Next
	}

	return cur
}

你可能感兴趣的:(算法,数据结构,go)