[Leetcode]环形链表II
题目描述
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。
说明:不允许修改给定的链表。
进阶:
你是否可以使用 O(1) 空间解决此题?
示例 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 <= 105
pos 的值为 -1 或者链表中的一个有效索引
实现代码
- 方法一: 一个非常直观的思路是:我们遍历链表中的每个节点,并将它记录下来,一旦遇到了此前遍历过的节点,就可以判定链表中存在环。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
dicts ={}
pos = head
while pos != None:
dicts[pos] = dicts.get(pos, 0) + 1
if dicts[pos] == 2:
return pos
pos = pos.next
return None
- 方法二: 快慢指针
- 参考题解
- 定义一个慢指针 s l o w slow slow、一个快指针 f a s t fast fast, s l o w slow slow每次走一步, f a s t fast fast每次走两步,如果有环一定会相遇,此时, f a s t fast fast所走距离为 s l o w slow slow所走距离的2倍,即 f = 2 s ① f=2s ① f=2s①
- 假设链表头节点到链表第一个入环的节点距离为 a ,链表环内距离为 b,那么,两指针都是先走距离 a ,然后 f a s t fast fast 比 s l o w slow slow在环内多走 n ( 不 确 定 ) n(不确定) n(不确定)圈,然后相遇,即 f = s + n b ② f=s+nb ② f=s+nb②
- 根据①②得, s = n b s=nb s=nb, f = 2 n b f=2nb f=2nb
- 走完链表第一个入环的节点需要距离 a + n b a+nb a+nb,所以 s l o w slow slow还差 a 的距离走到,而 h e a d head head 与链表第一个入环的节点距离也为 a
- 所以当两指针第一次相遇后,让 f a s t fast fast指向 h e a d head head, s l o w slow slow不动,之后两指针都各走一步,当再次相遇时,即为链表第一个入环的节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
slow, fast = head, head
while slow != None and fast != None:
slow = slow.next
fast = fast.next.next if fast.next else None
if slow != None and fast != None and slow == fast:
fast = head
while slow != fast:
slow = slow.next
fast = fast.next
return fast
return None