LeetCode 142. Linked List Cycle II
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-cycle-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这道题是比较经典的链表题: 快慢指针。
讲快慢指针前, 需要讲一下一道小学题:环形追击
环形跑道的周长是800米,甲、乙两名运动员同时顺时针自起点出发,甲的速度是每分钟400米,乙的速度是每分钟375米,多少分钟后两人第一次碰面?甲、乙两名运动员各跑了多少米?甲、乙两名运动员各跑了几圈?
这就是一道典型的环内追击问题, 这里有个很容易想象的原理,当慢速员(乙)被快速员(快)追上的时候,慢速员(乙)只能落后快速员(甲)一圈,快速员(甲)只能领先慢速员(乙)一圈。
所以 环形周长 = (快速员速度 - 慢速员速度)* 时间
回到我们的快慢指针,当两个指针都在环的时候, 快指针 如果 需要追上 慢指针, 则需要领先快指针 c(环长) + (快指针 - 慢指针 的距离)
回到我们这个题目:
- 如果到达了链表的尾部, 就会出现 null 节点, 那么这个链表就不会成环
- 如果链表的尾部成环,那么我们设定的快慢指针总会相遇; 而追上的时候, 就是 快指针 需要 领先 慢指针的距离 = 环周长 + (慢指针 出发时 快指针距离慢指针的距离 == 慢指针入环前走的距离)
解题: 假设快指针fast 速度 为 q , 慢指针 slow 速度 为 p , 链表头距离环入口距离为 m, 环周长为 l
快指针是慢指针速度的 n 倍, q = np;
如果 链表成环时, fast 走的距离 是 Q, slow 走的距离是 P, Q = nP;
那么 Q - P = l + (l - m)
nP - P = 2l - m
(n-1)P = 2l - m
这里说明了, 第一次相遇时 fast 和 slow 在环的位置 肯定就是 距离入环处 距离为 m, 所以只要 再 重新走 距离 m 就能找到 入环口。
反过来说, 首先让快指针 慢下来 跟 慢指针速度一致, 然后让快指针冲链表头出发, 那么相遇的地方就是环的入口了。
附上算法.
1 | /** |
备注: 这里的快指针一般指为慢指针的两倍速度, 原因就是进入循环前 只用 判断前两个节点是否为空, 当然也可以设置其他倍数, 也要注意进入循环前, 需要判断多几个节点 是否为空就好。