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

链表中环的入口结点

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

一、题目描述

NC3链表中环的入口结点
题目描述:给定一条链表,若链表存在环,就请找到环的入口并返回入口的指针;若不存在环就返回null

二、算法1(哈希集合)

解题思路:

一个直观的想法就是用哈希表存下我们从链表头往下走路径所见过的节点指针,当出现已经记录过的节点时,这个节点就是环的入口节点

代码实现(C++11)

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        unordered_set<ListNode*> st;    // 哈希集合
        while(pHead){
            if(st.count(pHead)) return pHead;    // 若已经记录过,直接返回
            st.insert(pHead);    // 记录当前结点
            pHead = pHead->next;
        }
        return nullptr;    // 无环
    }
};

时间复杂度:O(n), n为链表长度,遍历一次链表的时间复杂度为O(n)
空间复杂度:O(n),哈希集合所用的空间

三、算法2(快慢指针)

解题思路

  1. 我们知道,用快慢指针可以很容易判断一条链表是否存在环,快指针fast每次走两步,慢指针slow每次走一步,那么若进入环中,每次他们之间的相对距离都会-1,直到两者相遇。虽然这能很快的知道是否存在环,但是它能否帮我们找到环的入口呢,答案是肯定的
  2. 假设从头节点到环的入口节点的前一个节点一共有a个,环中的节点有b个,设fast指针走过的节点数是f,slow指针走过的节点数是s,那么有以下两个结论:
  • f = 2 * s (即快指针走过的节点数一定是慢指针的两倍)
  • f = s + nb (当两者相遇时,快指针一定已经绕环走了n圈)

由上面两个等式可以得出,f = 2nbs = nb
故可知,两指针相遇时,慢指针已经走了nb步,已知我们要走到入口节点,需要走a + kb步,而这时s = nb只要再走a即可到达入口,我们把快指针移动到头节点,然后两个指针一步一步往后走,当它们相遇时所处的位置就是入口节点

图片说明

代码实现(C++11)

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        ListNode *fast = pHead, *slow = pHead;    // 快慢指针一开始都指向头
        while(fast){
            slow = slow->next;    // 慢指针走一步
            if(fast->next == nullptr) return nullptr;    // 若快指针的下一步不能走,则说明两指针不会相遇
            fast = fast->next->next;    // 快指针向后走两步
            if(fast == slow){    // 找到相交节点, 此时慢指针已经走了nb步
                fast = pHead;    // 快指针重新移动到头
                while(fast != slow){    // 直到两指针相遇位置,每次向后走一步
                    fast = fast->next;
                    slow = slow->next;
                }
                return fast;    // 找到入口节点,直接返回
            }
        }
        return nullptr;
    }
};

时间复杂度:O(n),n为链表节点数,以慢指针为基准,遍历次数约为2次,故时间复杂度为O(n)
空间复杂度:O(1),只使用了两个指针变量,空间复杂度为常数

全部评论
f = s + nb 这个式子不就是以入口节点就是相遇节点为前提得到的吗,再由这个式子推导相遇点是入口节点当然是正确的
1 回复 分享
发布于 2022-06-11 12:34
比官方的写的对
1 回复 分享
发布于 2022-03-30 10:54
写的很清楚
1 回复 分享
发布于 2021-11-30 12:39
这个解释基本上相当于证明了,说得很清楚:https://zhuanlan.zhihu.com/p/103626709
2 回复 分享
发布于 2022-11-08 16:41 浙江
解释中有一点没有说得很清楚:慢指针走了s=nb步后,再走a步,到达入口节点,其实并非一定是首次到达,只是再走a步后,快慢指针恰好在入口点相遇了
2 回复 分享
发布于 2022-11-08 16:27 浙江
nb
2 回复 分享
发布于 2022-05-25 09:36
只是取了简单情况,实际上可以重叠n次
点赞 回复 分享
发布于 2023-03-06 13:25 北京
要改为“快指针移动的次数一定是慢指针移动次数的的两倍”这种理解才是恰当
点赞 回复 分享
发布于 2022-06-25 21:43
这个写的挺好的
点赞 回复 分享
发布于 2022-05-28 15:56

相关推荐

牛客刘北:如果暑期实习是27届的话,你要晚一年才会毕业,企业为什么会等你呢?要搞清时间逻辑呀!27届现在实习只能是在暑假实习,这是日常实习,不是暑期实习。所以多去投日常实习吧,暑期实习肯定不会要你的
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
69
18
分享

创作者周榜

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