力扣142. 环形链表
1 力扣142. 环形链表 II
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始
)。如果 pos
是 -1
,则在该链表中没有环。
pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改链表。示例 1:
|
|
示例 2:
|
|
示例 3:
|
|
提示:
- 链表中节点的数目范围在范围 [0, 104] 内
- -105 <= Node.val <= 105
- pos 的值为 -1 或者链表中的一个有效索引
进阶:你是否可以使用 O(1) 空间解决此题?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-cycle-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2 哈希表
2.1 思路与算法
遍历链表中的每个节点,并记录下来。一旦遇到之前保存过的节点,就可以判定为环形链表。为了方便查询,使用哈希表结构实现。
2.2 代码实现
- C++ 实现
|
|
- Java 实现
|
|
2.3 复杂度分析
时间复杂度:O(N),其中 N 为链表中节点的数目。需要访问链表中的每一个节点。 空间复杂度:O(N),其中 N 为链表中节点的数目。需要将链表中的每个节点都保存在哈希表当中。
3 快慢指针
3.1 思路与算法
使用两个指针,fast
与 slow
。它们起始都位于链表的头部。随后,slow
指针每次向后移动一个位置,而 fast
指针向后移动两个位置。如果链表中存在环,则 fast
指针最终将再次与 slow
指针在环中相遇。
3.2 代码实现
- C++ 实现
|
|
- Java 实现
|
|
3.3 复杂度分析
- 时间复杂度:O(N),其中 N 为链表中节点的数目。在最初判断快慢指针是否相遇时,slow 指针走过的距离不会超过链表的总长度;随后寻找入环点时,走过的距离也不会超过链表的总长度。
- 空间复杂度:O(1)。只使用了三个指针。
4 快慢指针的数学分析
4.1 快慢指针的相遇问题
如下图所示,设链表中环外部分的长度为 a
。slow
指针进入环后,又走了 b
的距离与 fast
相遇。此时,fast
指针已经走完了环的 n
圈,因此它走过的总距离为 a + n(b + c) + b = a + (n + 1)b + nc
。
设 fast
指针走过的距离都为 slow
指针的 x
倍,因此有 a + (n + 1)b + nc = x(a + b)
⟹ (b + c)n = (x − 1)(a + b)
。即从相遇点到入环点的距离加上 n
圈的环长,恰好等于从链表头部到入环点的距离的 x - 1
倍。
若 x = 2
,快指针步长为慢指针的 2 倍,(b + c)n = a + b
方程组有解。若 x = 3
,快指针步长为慢指针的 3 倍,(b + c)n = 2(a + b)
方程组有解。
4.2 循环圈的起始位置问题
由 (b + c)n = (x - 1)(a + b)
方程可知从相遇点到入环点的距离是环长的倍数。因此,当发现 slow
与 fast
相遇时,我们再额外使用一个指针 ptr
。起始位置指向链表头部,随后它和 slow
每次向后移动一个位置。最终,它们会在入环点相遇。