重要力扣每日一题.NO141.环形链表

Posted 东条希尔薇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重要力扣每日一题.NO141.环形链表相关的知识,希望对你有一定的参考价值。

画图讲解和源代码已上传至我的码云

原题地址

题目描述

给定一个链表,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

思路求解

笔者先说一句:向想出这个算法的大佬致敬!能想出这个办法,真的是太聪明了!

这个算法非常想我们高中物理必修1学过的追及相遇问题

具体思路如下:

我们定义一对快慢指针

快的每次走两步,慢的每次走一步

这样,它们两个如果入了环,快的一定是会追上慢的

如果快的和慢的相遇了,则链表就有环,

如果没有相遇,而是fast走向NULL了,链表就没有环

什么?你问我为什么快的一定会追上慢的?这要问你高中物理老师了,这个我帮不了你(doge)

画图求解

代码实现(c语言)

bool hasCycle(struct ListNode *head) {
    struct ListNode* slow=head,*fast=head;
    while(fast&&fast->next)//判断有没有环的条件
    {
        
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)//相等,证明有环了
            return true;
        
    }
    
    return false;
}

但其实这个追及问题跟物理上的还不太一样,链表这里的运动轨迹是离散的点,而物理中的追及,它们的运动轨迹是连续的

所以有了以下的问题
思考问题(重要)

  1. 为什么这个算法成立?给出数学证明
  2. 为什么一定要2Vslow=fast?能不能推广到nVslow=fast?(即fast的速度是slow的任意倍)

第一个问题的证明:

  • fast一定先进环,slow此时走了圈外的1/2(这条为公理,不证明)
  • slow进环后,fast已经走了一段,与slow相距多少和圈的大小有关,我们可以先设为x

那么,它们之间的距离会存在以下关系

初始:x
遍历一次:x-1
遍历两次:x-2

最后一次:1,
结束:0
。。。

我们可以发现,它们之间的距离每次都是-1,所以能够保证它们的距离一定能减到0

第二个问题的证明

结论:不一定

我们在这里设它们之间的速度为3倍关系

这样,可以得到它们的速度差为2,即它们之间的距离每次都减2

它们的距离会有以下关系

x
x-2
x-4
.
.
.
2?
1?

最后两项值得考究

因为我们可以发现,当它们之间的距离为x-2时,这时候再减二,就刚好相遇了

但是当距离为x-1时,这时再减二,它们之间的距离就是-1,这说明slow已经反超了fast!

再经过简单的数学推理,可以得出结论

当距离是-1后,它们之间的距离(大圈举例如果还是奇数,将永远追不上了)

画图求解:

投票直通车

以上是关于重要力扣每日一题.NO141.环形链表的主要内容,如果未能解决你的问题,请参考以下文章

「 每日一练,快乐水题 」141. 环形链表

「 每日一练,快乐水题 」141. 环形链表

力扣每日一题NO.160.相交链表

力扣每日一题NO.622——循环队列

精选力扣500题 第11题 LeetCode 141. 环形链表 c++详细题解

「 每日一练,快乐水题 」141. 环形链表