leetcode 142. 环形链表 II
给定一个链表的头节点 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 <= 105
-
pos
的值为-1
或者链表中的一个有效索引
进阶:你是否可以使用 O(1)
空间解决此题?
Related Topics
哈希表
链表
双指针
思路1:哈希表
将节点放入哈希表中,如果存在环,那么肯定在哈希表中出现。
public ListNode detectCycle(ListNode head) { HashSet<ListNode> set = new HashSet<ListNode>(); ListNode p = head; while(p!=null && !set.contains(p)){ set.add(p); p = p.next; } return p; } 解答成功: 执行耗时:3 ms,击败了20.80% 的Java用户 内存消耗:42.3 MB,击败了5.02% 的Java用户
思路2:快慢指针
参考leetcode官方:力扣
分析:(fast每次走2步,slow走一步) 环外部分长度为a,在环中走了b步相遇,环的剩下一部分为c。
-
当快慢指针相遇时,fast已经走了
a+n(b+c)+b
步。而slow走了a+b
步,那么a+n(b+c)+b = 2(a+b)
-
由上式可以推出
a = (n-1)(b+c)+c
,从这个结果可以得出,从表头到环口的距离是a,刚好等于把环走了n-1圈加c步。快慢指针相遇的点刚好离环口的距离是c步。 -
那么从相遇点和表头同时走,刚好在环扣相遇。
public class Solution { public ListNode detectCycle(ListNode head) { ListNode slow = head; ListNode fast = head; ListNode p = head; while(fast!=null && fast.next!=null){ slow = slow.next; fast = fast.next.next; //说明有环 if(slow == fast){ while(p!=slow){ p = p.next; slow = slow.next; } return p; } } return null; } } 解答成功: 执行耗时:0 ms,击败了100.00% 的Java用户 内存消耗:41.6 MB,击败了29.03% 的Java用户