题目信息
给定一个链表的头节点
head,返回链表开始入环的第一个节点。 如果链表无环,则返回null。如果链表中有某个节点,可以通过连续跟踪
next指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos来表示链表尾连接到链表中的位置(索引从 0 开始 )。如果pos是-1,则在该链表中没有环。注意:pos不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。示例 2:
输入:head = [1,2], pos = 0 输出:返回索引为 0 的链表节点 解释:链表中有一个环,其尾部连接到第一个节点。示例 3:
输入:head = [1], pos = -1 输出:返回 null 解释:链表中没有环。提示:
- 链表中节点的数目范围在范围
[0, 104]内-105 <= Node.val <= 105pos的值为-1或者链表中的一个有效索引进阶: 你是否可以使用
O(1)空间解决此题?
思路 / 启发过程
感想是看了答案我基本上不可能会做的....
我的理解上来说,答案的核心,首先要理解快慢指针的做法,然后就是用数学来解答。数学解答的核心偏向于距离表达和速度表达吧,去建立等量关系(相遇本质上就是一种路程相等的等量关系)。从表达式揭露的关系下手,然后去看怎么建立算法和解答方法
参考答案思维过程
关键是:相遇点到环入口的距离,和头节点到环入口的距离存在数学关系。
设:
a:头节点到环入口的距离
b:环入口到相遇点的距离
c:环的长度
相遇时:
slow 走了:a + b
fast 走了:a + b + k*c
这里注意一个细节,slow一定是在进入的第一圈就被fast追上了。原因:slow进入环后,和fast的距离肯定是 <= m的,而fast每次都会缩小和slow之间的,一个单位的距离,所以必定在slow走完第一个完整的环前,二者就相遇了。
因为 fast 速度是 slow 的两倍:
2(a + b) = a + b + k*c
整理得到:
a + b = k*c
所以:
a = k*c - b
也即:
a = (k - 1)c + (c - b)
这意味着:
从相遇点继续走 c - b 步,会到达环入口
从头节点走 a 步,也会到达环入口
而多走完整的 (k - 1)c 圈不会改变环上的位置。
因此相遇后:
- 保留一个指针在相遇点。
- 把另一个指针重新放回头节点。
- 两个指针都每次走一步。
- 它们下一次相遇的位置就是环入口。
通过示例代码
python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 承接环形链表1的部分,先找到相遇点
fast = head
slow = head
while fast is not None and fast.next is not None:
slow = slow.next
fast = fast.next.next
if slow is fast: # has circle
# 开始找相遇节点
fast = head # 一个节点回到头部位置
while slow != fast:
fast = fast.next
slow = slow.next
return fast
return None
知道逻辑了以后写代码还是很好写的...主要是逻辑和思维过程


