题目简述:
给定一个链表的头节点
head,返回链表开始入环的第一个节点。 如果链表无环,则返回null。如果链表中有某个节点,可以通过连续跟踪
next指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos来表示链表尾连接到链表中的位置(索引从 0 开始)。如果pos是-1,则在该链表中没有环。注意:pos不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。
题目链接:142. 环形链表 II
要做重复检验当然可以考虑哈希表了,只是存在额外的空间开销,但也是一种方法,空间复杂度为
/**
* 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<ListNode> set = new HashSet<>();
ListNode curr = head;
while (curr != null) {
if (set.contains(curr)) return curr;
set.add(curr);
curr = curr.next;
}
return null;
}
}还是那句话,既然看到链表了,那一定要考虑双指针。事实上,双指针可以只使用
- 首先用快慢指针检测环路,如果不存在直接返回
null; - 如果存在环路,则在检查出环路时在标头重新放置一个慢指针(原有慢满指针继续自增,但快指针我们已经不需要了),那么下一次两个慢指针相遇时的位置即为环路起始节点。
假设非环路部分长
首先证明为何如果存在环路则快慢指针必然能够相遇。假设慢指针走过了
根据同余的性质,
$$
\begin{align}
&\ \ \ \ \ \ (n^{\ast}-\text{len}A)\equiv(2n^{\ast}-\text{len}A)\ \ (\mathrm{mod}\ ,,\text{len}B)\
&\Leftrightarrow n^{\ast}\equiv 2n^{\ast}\ \ (\mathrm{mod}\ ,,\text{len}B)\
&\Leftrightarrow n^{\ast}\equiv 0\ \ (\mathrm{mod}\ ,,\text{len}B)\
\end{align}
$$
因此必然存在这样的
接下来证明为什么当
接下来,程序是很容易编写的了。
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 (slow == fast) {
ListNode temp = head;
while (temp != slow) {
temp = temp.next;
slow = slow.next;
}
return temp;
}
}
return null;
}
}