1、环形链表

题目:https://leetcode.cn/problems/linked-list-cycle-ii/description/

①使用哈希表

public class Solution {
    public ListNode detectCycle(ListNode head) {
         Set<ListNode> visited = new HashSet<ListNode>();
         ListNode pa=head;
         while(pa!=null){
            if(visited.contains(pa)){
                return pa;
            }
            visited.add(pa);
            pa=pa.next;
         }
         return null;
    }
}

②使用快慢指针

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 index1=head;
                ListNode index2=slow;
                    while(index1!=index2){
                        index1=index1.next;
                        index2=index2.next;
                    }
                    return index1;
            }
        }
        return null;
    }
}

问题:

快指针每次走两步,慢指针每次走一步,为什么有环就一定会相遇?

没有环,则一定不会相遇。

有环,快指针先进入环,接着慢指针进入,快指针相当于每次以一步的速度去追赶慢指针,所以一定会相遇。

如果找到环的入口?

不论快指针在环里走了几圈,不论n=几 y+z都是环的距离,即最后x=z;那么当相遇时,我们设置一个从head出发,一个从相遇位置出发,则最后两个指针相遇的位置就是环的入口。

为什么慢指针走的是 x+y 而不是x+y+k(y+z)呢?即为什么慢指针在环里走不到一圈就一定会相遇。

我们可以把环摊开,

首先slow进环的时候,fast一定是先进环来了。

如果slow进环入口,fast也在环入口,那么把这个环展开成直线,就是如下图的样子:

可以看出如果slow 和 fast同时在环入口开始走,一定会在环入口3相遇,slow走了一圈,fast走了两圈。

重点来了,slow进环的时候,fast一定是在环的任意一个位置,如图:

那么fast指针走到环入口3的时候,已经走了k + n 个节点,slow相应的应该走了(k + n) / 2 个节点。

因为k是小于n的(图中可以看出),所以(k + n) / 2 一定小于n。

也就是说slow一定没有走到环入口3,而fast已经到环入口3了

这说明什么呢?

在slow开始走的那一环已经和fast相遇了