题目
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
.
To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.
.
Note: Do not modify the linked list.
给定一个链表,返回环开始的结点。如果没有环,则返回null.
样例输入输出
为了表示给定的链表中的环,我们用整数pos来代表链表中尾结点连接到的位置。如果pos值为-1,则代表链表中没有循环。
样例1:
输入:head = [3,2,0,-4],pos = 1
(表示一个含有3、2、0、-4四个结点的链表,且尾结点-4指向位置为1的结点2)
输出:1
(表示环开始的结点是位置为1的结点)
样例2:
输入:head = [1,2],pos = 0
输出:0
样例3:
输入:head = [1],pos = -1
输出:-1
思路
基于141题【Leetcode 141】Linked List Cycle - EASY的使用HashSet的思路,
这里仍然可以使用HashSet。
题解
/**
* 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) {
HashSet nodesVisited = new HashSet();
while(head!=null){
if(nodesVisited.contains(head)){
return head;
}
else{
nodesVisited.add(head);
head=head.next;
}
}
return null;
}
}
反思
复杂度分析
时间复杂度:O(n).
空间复杂度:O(n).
思路反思
由于该题是141题的升级,我们可以考虑能否使用141题使用的快慢指针的方法,将空间复杂度降至O(1)。
扩展学习
我们尝试使用快慢指针的方式,先来分析以下这张图:
我们可以得知,链表长度为a+b+c,环的长度为b+c。
快指针fp从头结点开始,以2结点/次的速率移动;
慢指针sp从头结点开始,以1结点/次的速率移动。
当快慢结点在C点首次相遇时,sp一定还没走完环的一圈,而fp已经在环内走了n圈(n≥1).
Lfp = (a + b) + n (b + c) (n ≥ 1)
Lsp= a + b
.
又因为Lfp = 2Lsp
有 2(a + b) = (a + b) + n (b + c)
得到 a = c + (n - 1)(b + c) (n ≥ 1)
我们得到的式子a = c + (n - 1)(b + c)(n ≥ 1)有什么具体含义呢?
意思是a的长度比c的长度多出的是环长的整数倍(可能为0)。
于是,此时我们将快指针fp指向头结点A,速率改为1结点/次。
然后让fp和sp同时移动。
那么如果二者相遇,一定是在环上,有Lfp ≥ a。
而当fp到达B点时,刚好Lsp=Lfp = a = c + (n - 1)(b + c)(n ≥ 1),则sp也刚好到达B点。即两者再次相遇的点就是环开始的点。
代码如下:
/**
* 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 || head.next == null){
return null;
}
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
break;
}
}
if(fast == null || fast.next == null){
return null;
}
fast = head;
while(fast!=slow){
fast = fast.next;
slow = slow.next;
}
return fast;
}
}
时间复杂度为O(n).
空间复杂度为O(1).