算法热门:环形链表I(LeetCode 141)

Posted 白龙码~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法热门:环形链表I(LeetCode 141)相关的知识,希望对你有一定的参考价值。

你可能看过这道题的题解,但不一定看过对它深入的证明,而今天我的任务就是这个;

我们知道,链表拥有两种形态:单链表以及循环链表,其中,单链表指的是:链表仅有一个数据存储变量va和一个指向下一个结点的指针,而循环链表在单链表的基础上加了一个指向上一节点的指针;而我们今天所讨论的环形链表,不仅囊括了循环链表这种链接头尾的情况,还囊括了其它带环的情况——

情况分析

我们知道,循环链表的构成是这样的——
在这里插入图片描述
它的环是连接头尾的大环
而环形链表的环除此之外也可以是——
在这里插入图片描述
也就是说,链表中某两个结点相链接,构成了一个环,此外,带环的链表是单链表;

题目分析

我们来看具体题目:
在这里插入图片描述
这是我们需要完善的函数体
在这里插入图片描述
可以看到,题中的pos实际上是主函数部分的变量,用来形成一个环形链表,而对于只要完善函数的OJ题,由于函数的参数列表没有pos,并且返回值是一个bool值,所以我们不需要考虑pos这个变量。
那么所有的问题都集中在一个上面:如何判断链表是否带环?

最容易想到的是哈希表的思想,也就是说:每次都让指针走一个结点,然后判断这个节点之前是否出现过,不过对于绝大部分初学者而言,哈希表仅有耳闻而未接触,所以我们今天需要另想一种方法;

我们先简化一个环形链表的模型:
在这里插入图片描述
经历过前面的刷题我们发现,快慢指针法在链表OJ题中经常出现,那么这题我们是否也能采取快慢指针的方法呢?假设慢指针一次走一个结点,快指针一次走两个结点,那么快指针必然会在慢指针之前走到链表环的入口点;
在这里插入图片描述
当快慢指针继续走下去的时候,慢指针也会进入环,而快指针此时已经在环内走了N圈了;
在这里插入图片描述
当这种循环再进行下去,fast指针如果追上slow指针,就能判断出,链表有环;

问题来了,fast指针真的会追上slow指针吗?

证明

在这里插入图片描述
我们假设链表的头到环的入口的距离为L,环的长度为C,slow进入环后,与fast之间的距离为X;由于fast指针一次走两个节点,slow一次走一个节点,也就是说,fast指针比slow指针多走一步,那么如果它们继续走下去,则fast指针必然会追上slow;
如果还不理解,我们不妨把这样的一个追逐问题化为一条直线上的追逐问题:
在这里插入图片描述
假设还需走n次fast追上slow,那么也就是说:
在这里插入图片描述
解出来:n=x

也就是说,只要这样的循环再进行x次,fast必然会追上slow;
如果链表没有环,那么由于fast走得快,slow永远不可能追上它,从而我们可以判定:环存在!

代码实现

bool hasCycle(struct ListNode *head) {
    struct ListNode* slow=head,*fast=head;
    while(fast && fast->next)//由于fast一次走两个结点,那么需要保证fast和fast的next都不为空
    {
        fast=fast->next->next;//快指针走两个结点
        slow=slow->next;//慢指针走一个
        if(fast==slow)//快慢指针相遇
        {
            return true;
        }
    }
    return false;
}

思考

当快指针一次走两结点,慢指针一次走一节点,那么快指针必然会追上慢指针;如果是其他情况呢?比如快指针走三个节点,甚至四个、五个、n个……
我们讨论快指针走三个结点的情况:
在这里插入图片描述
同样是这个图,slow与fast之间相差x
由于fast指针与slow指针的步长差为2,所以他们之间的距离变化为:
X-2
X-4
X-6

X-2N

当X是偶数时,X-2N可以为0,那么它们最终也可以相遇;

当X为奇数时,我们再看一下这个图:
在这里插入图片描述

当slow刚走到环入口时,slow指针走了L,fast指针走了nC+C-X,其中,n表示fast指针在slow入环之前在环内绕了n圈;又因为fast指针一次走两个节点,那么就满足:
在这里插入图片描述
如果X为奇数,那么(n+1)C就要是奇数,则n+1和C都要是奇数(偶数与任何数相乘都为偶数)
回到上面的X-2N的式子:
在这里插入图片描述
由于X为奇数,那么X-2N所得到的最小正整数为1,即:
在这里插入图片描述
当fast和slow之间的距离再次为X时,假设slow走了m次,则需要满足:

在这里插入图片描述
由于m小于C,也就是说,slow没走几步,就在一圈之内被fast又追上了,此时他们之间的距离为X,这就又回到了一开始的那样,然后又要X-2,X-4…X-N,如此循环往复,fast永远追不上slow!

小结

创作不易,留个点赞评论再走吧~关注博主,分享更多学习、刷题经验

以上是关于算法热门:环形链表I(LeetCode 141)的主要内容,如果未能解决你的问题,请参考以下文章

leetcode算法141.环形链表

算法热门:环形链表的又一解法(LeetCode 142)

Leetcode141. 环形链表(JAVA经典快慢双指针)

算法-leetcode-142. 环形链表 II

[算法] leetcode单链表相关题目详解

LeetCode刷题141-简单-环形链表