题解 | #链表中环的入口结点#

链表中环的入口结点

http://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4

题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
输入描述:输入分为2段,第一段是入环前的链表部分,第二段是链表环的部分,后台将这2个会组装成一个有环或者无环单链表
返回值描述:返回链表的环的入口结点即可。而我们后台程序会打印这个节点
示例1
输入:{1,2},{3,4,5}
返回值:3
说明:返回环形链表入口节点,我们后台会打印该环形链表入口节点,即3

题目分析

图片说明
有环的链表,在遍历时会在环中一直循环,想要获得环的入口结点,直观地想,可以使用hash法保存出现的结点,当重复环的遍历过程时,第一次碰到重复的结点即为环入口结点B。

解题思路

方法1:hash法,记录第一次重复的结点
通过使用set或者map来存储已经遍历过的结点,当第一次出现重复的结点时,即为入口结点。

方法2:快慢指针
通过定义slow和fast指针,slow每走一步,fast走两步,若是有环,则一定会在环的某个结点处相遇(slow == fast),根据下图分析计算,可知从相遇处到入口结点的距离与头结点与入口结点的距离相同。
图片说明

代码实现

方法1:hash法,记录第一次重复的结点

public ListNode EntryNodeOfLoop(ListNode pHead) {
        // 使用set来记录出现的结点
        HashSet<ListNode> set = new HashSet<>();
        while(pHead != null){
           // 当set中包含结点,说明第一次出现重复的结点,即环的入口结点
            if(set.contains(pHead)){
                return pHead;
            }
            // set中加入未重复的结点
            set.add(pHead);
            pHead = pHead.next;
        }
        return null;
    }

时间复杂度:O(n),需要将链表的所有结点遍历一遍,时间复杂度为O(n);
空间复杂度:O(n),需要额外的n空间的hashset来存储结点。

方法2:快慢指针

public ListNode EntryNodeOfLoop(ListNode pHead) {
        if(pHead == null) return null;
        // 定义快慢指针
        ListNode slow = pHead;
        ListNode fast = pHead;
        while(fast != null && fast.next != null){
            // 快指针是满指针的两倍速度
            fast = fast.next.next;
            slow = slow.next;
            // 记录快慢指针第一次相遇的结点
            if(slow == fast) break;
        }
        // 若是快指针指向null,则不存在环
        if(fast == null || fast.next == null) return null;
        // 重新指向链表头部
        fast = pHead;
        // 与第一次相遇的结点相同速度出发,相遇结点为入口结点
        while(fast != slow){
            fast = fast.next;
            slow = slow.next;
        }
        return fast;
    }

时间复杂度:O(n),需要将链表的所有结点遍历一遍,时间复杂度为O(n);
空间复杂度:O(1),需要额外两个快慢指针来遍历结点。

全部评论
分析错了,记相遇点到入口的距离是z,那么x=z+(n-1)(z+y),当n=1的特殊情况是x=z。当然代码没错,依然在入口处相遇。
2 回复 分享
发布于 2022-05-09 10:24
这个分析有问题,首次相遇时,快指针可能已经走了N圈
15 回复 分享
发布于 2022-05-22 14:37
准确来说应该是X+Y的距离是环周长的整数倍,不过代码这样写也没问题,先找到相遇点之后,slow走X步刚好走完整数倍圈,会出现在入口处
5 回复 分享
发布于 2022-05-28 18:49
已赞。发现优化点,add方法添加元素时,若此元素已存在,则返回false
4 回复 分享
发布于 2021-10-22 00:50
看看官方的,别被这个误导了
2 回复 分享
发布于 2023-06-05 13:13 新疆
这个分析里得问题楼上也都说了,所以并不是X+Y=C,而是X+Y=n*C,C代表loop的长,n>=1,不过最终结果是一样。
2 回复 分享
发布于 2022-09-01 17:03 湖北
方法2:快慢指针这句代码有bug: fast = fast.next.next; 当链表只有一个节点时,会报错
2 回复 分享
发布于 2022-08-19 14:58 北京
代码对的,分析有问题。
2 回复 分享
发布于 2022-06-21 12:09
不用说,抄的
1 回复 分享
发布于 2022-07-02 23:49
利用Hash判断是不是前提应该是链表中不存在重复元素
1 回复 分享
发布于 2022-07-01 11:33
if(fast == null || fast.next == null) return null;这一句没看懂,为什么还要 fast.next == null这一个?
1 回复 分享
发布于 2022-03-01 11:39
错的吧 这还能置顶
点赞 回复 分享
发布于 2024-11-22 12:07 湖北
太妙了,重新让快指针回去跑,刚好是入口节点
点赞 回复 分享
发布于 2024-05-08 20:33 湖北
hash法不行吧,题干要求空间复杂度O(1)
点赞 回复 分享
发布于 2023-10-17 17:50 湖南
快慢指针法有个前提,慢指针第一圈就相遇了。
点赞 回复 分享
发布于 2023-10-07 15:43 四川
套圈了怎么办 需要证明
点赞 回复 分享
发布于 2022-09-30 12:15 河北
面试时要你分析该怎么回答呢
点赞 回复 分享
发布于 2022-09-15 11:31 广东
当x>>y的时候,fast在圆圈里要走很多圈才能遇到slow吧
点赞 回复 分享
发布于 2022-08-23 09:12 陕西

相关推荐

King987:待优化的地方还是挺多的,可以参考一下我的作品优化一下,优化不好的话也可以找我
点赞 评论 收藏
分享
牛客49732338...:同志们,已拿下
我的OC时间线
点赞 评论 收藏
分享
评论
122
22
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务