描述

题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。

输入描述:

输入分为2段,第一段是入环前的链表部分,第二段是链表环的部分,后台将这2个会组装成一个有环或者无环单链表

返回值描述:

返回链表的环的入口结点即可。而我们后台程序会打印这个节点

示例
输入:{1,2},{3,4,5}
返回值:3
说明:返回环形链表入口节点,我们后台会打印该环形链表入口节点,即3    
引言

记住一点:遇到链表题目要画图

知识点:链表、双指针
难度:⭐⭐⭐


题解

解题思路

通过画图,可以得出基本思路和整个过程。

接着运用快慢指针,通过对路径的对比和计算,以及第二次相遇后,两指针刚好路程相差环长度的n倍

方法一:快慢双指针

图解

image-20210701012652956

image-20210701012952416

算法流程:
  • 我们假设 a为出发点到环入口长度,b为环长度
  • fast速度是slow 的两倍,当相遇时,设走过的路径长度为:slow = s ,fast = s + nb,即fast比slow多走了n圈环
  • 因为时间相同,fast速度为slow两倍,路径自然是slow的两倍,因此:2s = s + nb, 即 s = nb,
  • 因为速度不同,肯定能相遇,所以当第一次相遇时,slow走了nb步,fast走了2nb
  • 相遇后,让 fast重新从出发点按slow指针相同速度走
  • 因为此时 slow 已经走了 nb 的路程,fast走了2nb路程
  • 而正常情况走到环入口,最少需要走: a + b,目前slow走了nb步了,需要再走a步就能从相遇点走到环入口节点
  • 而当fast是从起点重新走到入口节点,刚好也是路程 a,刚好再次相遇,也就是刚好走到入口节点
  • 总的路程:slow = a + nb, fast = a + 2nb,刚好满足在入口节点相遇的路程
  • 很重要的一点:指针在走的过程中,从起点走到环里后,会一直在环里转圈
Java 版本代码如下:
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead) {
        ListNode slow = pHead, fast = pHead;
        while(true) {
            if(fast == null || fast.next == null) {
                // fast先走到null表示无环
                return null;
            }
            slow = slow.next;
            fast = fast.next.next;
            // 第一次相遇
            if(slow == fast) {
                break;
            }
        }
        // fast从出发点重新开始
        fast = pHead;
        // 第二次相遇
        while(slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;        
    }
}
Python 版本代码如下:
class Solution:
    def EntryNodeOfLoop(self, pHead):
        fast, slow = pHead, pHead
        while fast and fast.next:
            fast = fast.next.next  
            slow = slow.next  
            # 第一次相遇
            if fast and fast == slow: 
                # 从出发点重新开始
                slow = pHead  
                # 第二次相遇
                while fast != slow:  
                    fast = fast.next
                    slow = slow.next
                return fast
        return None
复杂度分析:

时间复杂度 O(N)
空间复杂度 O(1):指针为常数级别空间

总结:链表题多画图

方法二:哈希

解题思路:

只有入口节点才会重复走过,因此用hash记录走过的节点

Java 版本代码如下:
import java.util.*;
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead) {
        Set<ListNode> set = new HashSet<>();
        ListNode node = pHead;
        set.add(node);
        while(node!=null){
            node = node.next;
            // 只有入口节点才会重复走过
            if(set.contains(node)){
                break;
            }else
                set.add(node);
        }
        return node;
    }
}
复杂度分析:

时间复杂度 O(N)
空间复杂度 O(N):哈希需要N级别的空间