题意如下:
给定一个链表的头节点 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 解释:链表中没有环。
该题有两种做法:
1.快慢指针 slow:每次走一个节点 fast:每次走两个节点
以这张图举例:
此时我们需要找到第一个相遇的节点
不难发现slow走过的路程 *2 == *fast走过的路程 (3*2=6)
那么对于head来说,我们可以让其向后遍历一次,slow也向后遍历,发现恰好相遇。
故推测head与slow两指针相遇所走过的路程是相同的。
用代码来说就是:
while(head != slow)
{
head = head.next;
slow = slow.next;
}
//最终head与slow必定会相遇
以下为数学严谨证明(可以略过):
有slow*2=fast知: (a+b)*2 == a+b+c+b 即 c = a 但不要忘记这只是我们举得例子,实际可能fast走过好多圈 也就是 (a+b)*2 ==a+b+(c+b)*n(n>=1) 即 a = c + (n-1)*(c+b)
但注意到(c+b)实际上就是圆的周长 不管其有多少的循环最终的位置实际上不变,还是会与head在节点入口相遇
代码如下:
import java.util.HashMap;
import java.util.Map;
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 he = head;
while(he != slow)
{
he = he.next;
slow = slow.next;
}
return he;
}
}
return null;
}
}
2.Map记录每一个位置,如果出现重复位置的出现,就说明存在环
对于这种方法理解简单,代码简单 但唯一不足就是空间复杂度为O(N)
代码如下:
import java.util.HashMap;
import java.util.Map;
public class Solution {
public ListNode detectCycle(ListNode head) {
Map<ListNode, Integer> mp = new HashMap<>();
ListNode cur = head;
int pos = 0;
while(cur != null) {
if(mp.containsKey(cur)) {
return cur; // 找到入口
}
mp.put(cur, pos);
cur = cur.next;
pos++;
}
return null;
}
}
感谢你看到这里,喜欢的可以点点关注哦!