力扣 - 142. 环形链表 II
题目
思路1(哈希表)
- 利用哈希表HashSet,保存访问过的路径,如果未访问过,就add添加且返回true,如果已存在再添加的话就会返回该结点,而且该结点就是他们重合的结点,否则返回null
代码
import java.util.HashSet;
public class Solution {
public ListNode detectCycle(ListNode head) {
//利用哈希表不重复元素的特性来存储结点判断是否存在环
HashSet<ListNode> set = new HashSet<>();
//只要没到头且还没重合就一直循环
while (head != null) {
if (!set.add(head)) {
return head;
}
head = head.next;
}
//到末尾还是没有重合的话就是返回null
return null;
}
}
复杂度分析
- 时间复杂度:\(O(N)\)
- 空间复杂度:\(O(N)\)
思路2(双指针)
-
我们可以利用快慢指针,慢指针每次移动一个,快指针每次移动两个,如果确实存在环的话,最终一定会重合的
-
如果快指针最后为
null,肯定是到末尾了,就没有环 -
我们假设头结点到重合的结点这段长度为a,重合的结点到相遇的结点为
b,环的剩下部分为c- 由于再相同的时间内,
fast的速度是low的两倍,而low走的路程为a+b,fast为low的两倍那么路程应该是`2(a+b)`` - 由题分析可得,fast走过的长度为
a+b+c+b - 可得等式:
a+b+c+b = 2(a+b),得到c = a - 所以,我们可以等到相遇的时候再创建一个指向
head的指针,同时以相同的速度向前移动,等到相遇的时候就是我们要的环重合的结点

- 由于再相同的时间内,
代码
public class Solution {
public ListNode detectCycle(ListNode head) {
//定义快慢指针
ListNode slow = head;
ListNode fast = head;
//若为空或者只有一个元素时候就是无环的
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
//如果快慢指针重合就代表存在环,然后开始寻找重合点
if (fast == slow) {
//定义一个pre指针指向head,让pre和low同时移动,等到重合时就是指向重合的点
ListNode pre = head;
while (pre != slow) {
pre = pre.next;
slow = slow.next;
}
return pre;
}
}
return null;
}
}
复杂的分析
- 时间复杂度:\(O(N)\)
- 空间复杂度:\(O(1)\)
我走得很慢,但我从不后退!

浙公网安备 33010602011771号