LeetCode142 环形链表 II

101 阅读1分钟

leetcode.cn/problems/li…

image.png

解法一:快慢指针

基于juejin.cn/post/747423… 中的解法,当快慢指针相遇时,让其中任一个指针指向头节点,然后让它俩以相同速度前进,再次相遇时所在的节点位置就是环开始的位置。

原理分析

假设快慢指针相遇时,slow 走了 k 步,那么快指针 fast 一定走了 2k 步,这多走的 k 步其实就是 fast 指针在环里转圈圈,所以 k 的值就是环长度的「整数倍」。

image.png 假设相遇点与环的起点的距离为 m,那么结合上图的 slow 指针,环的起点距头结点 head 的距离为 k - m,也就是说如果从 head 前进 k - m 步就能到达环起点。

image.png 巧的是,如果从相遇点继续前进 k - m 步,也恰好到达环起点。

所以,只要我们把快慢指针中的任一个重新指向 head,然后两个指针同速前进,k - m 步后一定会相遇,相遇点就是环的起点了。

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func detectCycle(head *ListNode) *ListNode {
	if head == nil || head.Next == nil {
		return nil
	}
	slow, fast := head, head
	for fast != nil && fast.Next != nil {
		slow = slow.Next
		fast = fast.Next.Next
		if slow == fast { // 发现链表有环
			// slow回到起点,slow和fast以相同速度继续前进直到再次相遇
			slow = head
			for slow != fast {
				slow = slow.Next
				fast = fast.Next
			}
			return slow
		}
	}
	return nil
}