目录
- 题目描述:142. 环形链表 II(中等)
- 题目接口
- 解题思路
- 代码
- PS:
题目描述:142. 环形链表 II(中等)
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
LeetCode做题链接:LeetCode-环形链表 II
示例 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 或者链表中的一个有效索引
进阶: 你是否可以使用 O(1)
空间解决此题?
题目接口
/*** Definition for singly-linked list.* class ListNode {* int val;* ListNode next;* ListNode(int x) {* val = x;* next = null;* }* }*/
public class Solution {public ListNode detectCycle(ListNode head) {}
}
解题思路
参考题解:环形链表 II(双指针法,清晰图解)
遇到这种环相遇的问题,第一时间就考虑快慢指针的方法,如果没接触过这类问题,可以看我另一篇文章:环形链表
下面思路是在你理解了判断链表中是否有环的问题
的基础上来说的
思路:
- 假设有环,环的长度为b,起始位置到环的起点为a,
- slow走1步,fast走2步,第一相遇的时候
f = 2s
(slow = s,fast = f),因为fast是slow的两倍嘛 - fast 比 slow多走了 n 个环的长度,所以
f = s + nb
(快慢指针都走过前面的a步了,重合时,快指针就比慢指针多走n圈) - 上面两式相减:
s = nb,f = 2nb
- 有图可知:走
a+nb
步一定是在环入口,有上式可知:第一次相遇时慢指针已经走了nb
步 - 我们需要再走慢指针再走
a
步就到环入口,而快指针怎么办?答案是置于head
位置,也是再走a
步就到环入口 - 所以可以一起走
a
步,最终快慢指针相等的位置就是环入口位置了
具体步骤:
- 先构建一次相遇,慢指针走一步,快指针走两步,如果有环,最终在环中相遇
- 接着构建第二次相遇,慢指针位置不变,快指针位置置为head(也就是起始位置)
- 然后快慢指针现在都是同时走一步,直到相遇,相遇的位置就是环的起始结点
代码
/*** Definition for singly-linked list.* class ListNode {* int val;* ListNode next;* ListNode(int x) {* val = x;* next = null;* }* }*/
public class Solution {public ListNode detectCycle(ListNode head) {if (head == null) {return null;}// 快慢指针都从head开始ListNode slow = head;ListNode fast = head;do {if (fast == null || fast.next == null) {return null;}// 快慢指针的移动slow = slow.next;fast = fast.next.next;} while (slow != fast); // 快慢指针相遇则退出// 将快指针置于head(开头),慢指针不变,还是在环中fast = head;// 快慢指针再次相遇就是环起始节点while (fast != slow) {// 快慢指针的移动,现在都是一格一格移动(快指针不再移动两个格)fast = fast.next;slow = slow.next;}return fast;}
}
PS:
感谢您的阅读!如果您觉得本篇文章对您有所帮助,请给予博主一个赞喔~