链表中环的问题
是链表中环的问题
链表中环的问题
给定一个链表,判断链表中是否有环LeetCode141。如何找到环的位置,LeetCode142。
方法一:使用HashSet
最简单的方法就是使用Hash,遍历的时候将元素放入Map中,如果有环一定会发生碰撞,发生碰撞的位置一定就是入口的位置。代码如下:
public static boolean hasCycleByMap(ListNode head) {
//创建一个Set
Set<ListNode> seen = new HashSet<ListNode>();
while (head != null) {
if (!seen.add(head)) {
return true;
}
head = head.next;
}
return false;
}
方法二:使用快慢指针
慢指针一次走一步,快指针一次走两步,如果在某个位置快慢指针相遇,则说明有环,并记录第一次相遇的位置P,此时将快指针移到链表的头部,让快慢指针以相同的速度移动,下次相遇的位置,就是环的入口位置。
推导过程:
假设链表的头节点到环的入口点的距离为a,环的入口点到快慢指针相遇点的距离为b,快慢指针相遇点到环的入口点的距离为c。那么根据快慢指针的移动,我们可以得出下面两个等式:
1、慢指针移动的距离 = a + b
2、快指针移动的距离 = a + b + c + b
由于快指针的速度是慢指针的两倍,所以快指针走过的距离是慢指针的两倍,因此有:2 * (a + b) = a + b + c + b
化简上述等式可以得到:a = c
这意味着从链表头部到环的入口点的距离等于快慢指针相遇点再继续走到环的入口点的距离。因此,当慢指针重新指向头节点,并与快指针以相同的速度移动时,它们最终会在环的入口点相遇。
所以,根据上述的推导,我们可以确定找到的相遇节点就是链表中环的入口点。
实现代码如下
public static boolean hasCycleByTwoPoint(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow)
return true;
}
return false;
}