判断环形链表及寻找入环口问题详解

简介: 链表在面试和笔试中都是十分常见的问题。本篇文章会简述到判断环形链表和返回环形链表的入环点。其中有较多的细节,本篇文章会详细解释。

 链表在面试和笔试中都是十分常见的问题。本篇文章会简述到判断环形链表返回环形链表的入环点。其中有较多的细节,本篇文章会详细解释。



一、判断环形链表

1、1 题目描述


题目来源:Leetcode


题目难度:简单


题目描述:给你一个链表的头节点 head ,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。


 注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环 ,则返回 true 。 否则,返回 false 。


1b158af4ba014348acfedc398e7e683c.png

题目数据 保证 整个链式结构中不存在环。

 注意,函数返回结果后,链表必须 保持其原始结构

1、2 题解详细思路与解答



我们发现,环形链表是不能够随对其进行遍历的,如果不加任何操作,会很容易造成死循环。那怎么判断是否有环呢?我们不妨用一下追赶问题去考虑一下。也就是快慢指针。如果有环的话,快指针会先走进环内,并且一直在环内进行循环。慢指针会后进入环内。当两个指针都进入环内时,就成为了一个追击问题了。我们不妨设置快指针一次走两个节点,慢指针一次走一个节点,两个指针都进入环内就成为了快指针追击慢指针的情况了。此时如果有环一定会相遇。


 我们先看代码的实现:

bool hasCycle(struct ListNode *head) 
{
    if(head==NULL)
        return false;
    struct ListNode *slow=head,*fast=head;
    while(fast && fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)
            return true;
    }
    return false;
}


 上述代码中,如果没有环,当链表中节点个数为奇数时,fast->next 为空时是截至条件。当链表的节点个数为偶数时,fast 为空时是截至条件

二、找环形链表的入环点

2、1 题目描述



题目来源:Leetcode


题目难度:中等


题目描述:给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改链表。


ff32bf09358c4d78be767b61d4df1831.png



10f189a7ceb9467a96d21b45d87e4a81.png


2、2 题解思路

 当我们在做判断环形链表时,我们设置的快指针一次走两个节点,慢指针一次走一个节点。为什么要这样设置呢?那么快指针一次走三步、四步……呢?这其中到底与什么有关呢?我们继续往下分析。


2、2、1 为什么快指针每次走两步,慢指针走一步可以?


 假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚

进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。 此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况,因此:在满指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。

 我们发现上述重点是在分析的相对速度。即我们可以看成慢指针没有走,快指针每次走一步在追赶,不会错过的,一定会追上并且相遇的。


2、2、2 快指针一次走3步,走4步,...n步行吗?


为什么slow走1步,fast走x步(X>=3),他们会相遇?会不会错过?请证明。我们先来看快指针一次走3步,慢指针一次走1步的情况。


 假设slow进环的时候fast和slow之间距离是N。slow进环以后,fast开始追击slow,slow每走1步,fast走3步,他们之间的距离缩小2。假设fast和slow之间的距离为偶数,那么每次距离缩减2,那么一定会追上且会相遇。假设fast和slow之间的距离为奇数,第一圈fast会超过slow,会追上但不会相遇。那么第二圈的时候,它们之间的距离变成了N-1。距离就变成了偶数了,第二圈会追上且相遇。


那么快指针一次走4步,慢指针一次走1步的情况呢?我们再来分析一波。


 假设slow进环的时候fast和slow之间距离是N。slow进环以后,fast开始追击slow,slow每走1步,fast走4步,他们之间的距离缩小3。假设N是3的倍数,那么每次距离缩小3,第一圈就会追上并且相遇。那么如果N不是3的倍数,是N%3为2,第一圈并不会相遇,第二圈距离会变成N-1。(N-1)%3为1,第二圈又不会相遇。第三圈距离会变成N-1-2,我们发下减去3相当于没减。会一直循环下去,并不会相遇。当N%3为1时,与上述中的一种情况一样,也会陷入死循环。所以快指针一次走4步,慢指针一次走1步的情况是不行的。


77a570482e254756b8d485d4665f63f5.png



2、2、3 是否能够相遇关键因素

 通过上面的两种情况的分析,发现快慢指针能否相遇,关键是有两个因素:慢指针进环时与快指针之间的距离两者的相对速度。那怎么找入环点呢?

2、3 找入环点


我们接着分析:

 我们在这里不妨分析一下快慢指针的整个过程,如下图:

 我们就以快指针每次走两步,慢指针走一步的情况进行分析。那么当两个指针相遇时,slow一定时走的环形的第一圈。因为我们假如slow在环内走了一圈多,那么fast最少走了两圈,因为相对速度为1,追上即相遇,当fast走到两圈多的情况下早就相遇过,故slow走一圈多不成立。但是在slow入环之前,fast已经在环内走了很多圈(我们假设已经走了n圈,n可能等于1,2……)。故相遇时我们可以列出两者的距离等式:2*(L+X)=L+n*C+X。我们在对等式进行变换:L=n*C-X。我们在对等式进行分析:L为入环前的距离,n*C-X=(n-1)*C + C-X。这里我们这能算出C环的长度,其他的都是未知数。这个L=(n-1)*C + C-X等式也就意味着,在有环的情况下,一个指针从起始点走,一个指针从相遇点走,从相遇点走的指针可能在环内走了很多圈,也有可能一圈也没有,那么两个点再次相遇的位置即为入环点的位置了。我们再看代码:

struct ListNode *detectCycle(struct ListNode *head) 
{
  if(head==NULL)
        return NULL;
    struct ListNode* fast=head,*slow=head;
    while(fast && fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(fast==slow)
        {
            struct ListNode* meet=fast;
            struct ListNode* phead=head;
            while(phead!=meet)
            {
                phead=phead->next;
                meet=meet->next;
            }
            return meet;
        }
    }
    return NULL;
}

三、总结



 上述的问题在面试中很常见,问怎么看是否有环,为什么快指针每次走两步,慢指针走一步可以?快指针一次走3步,走4步,...n步行吗?还有一个就是找入环点的位置。希望本编文章会对你有所帮助,可以很好的解决这些问题。一定要搞清楚细节问题,不要只记结论,否则会吃大亏。


 本篇文章的讲解就到这里,希望以上内容会对你有所帮助,感谢观看ovo~

相关文章
|
6月前
|
存储 C语言 索引
环形链表、环形链表 II、有效的括号​​​​​​​【LeetCode刷题日志】
环形链表、环形链表 II、有效的括号​​​​​​​【LeetCode刷题日志】
|
5月前
|
Java
环形数组链表(java)
环形数组链表(java)
|
30天前
【数据结构】环形、相交、回文、分割、合并、反转链表
【数据结构】环形、相交、回文、分割、合并、反转链表
23 0
|
4月前
【数据结构OJ题】环形链表
力扣题目——环形链表
36 3
【数据结构OJ题】环形链表
|
4月前
【数据结构OJ题】环形链表II
力扣题目——环形链表II
29 1
【数据结构OJ题】环形链表II
|
5月前
|
存储 算法 Java
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
48 2
|
4月前
|
Java 索引
力扣经典150题第五十六题:环形链表
力扣经典150题第五十六题:环形链表
32 0
|
5月前
|
Java
单向环形链表-约瑟夫问题(java)
单向环形链表-约瑟夫问题(java)
|
5月前
|
存储 算法 C语言
【数据结构与算法 刷题系列】环形链表的约瑟夫问题
【数据结构与算法 刷题系列】环形链表的约瑟夫问题
|
6月前
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点.
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点
50 1