链表oj--数据结构--c语言--环形链表(1)(2)(以及笔试题slow一次走1、n步,fast一次走2、3、m步一定会相遇吗讲解)

本文介绍了如何使用快慢指针检测环形链表的存在,并探讨了不同步速下(如一次一步和一次两步、一步和三步)快慢指针相遇的可能性,以及如何找到环的入口。通过实例和代码演示了解环形链表的典型问题解决方法。
摘要由CSDN通过智能技术生成

目录

一、【环形链表1】. - 力扣(LeetCode)

A.思路

1.判断是否有环

B.我们可以通过以上思路写出代码:

C.笔试题

1、slow一次走一步,fast一次走两步一定会相遇吗?(一定会)

2、slow一次走一步,fast一次走三步一定会相遇吗?(一定能追上)

总结:

3、slow一次走n步,fast一次走m步一定会相遇吗?(m>n>1)

二、【环形链表2】(返回环的入口). - 力扣(LeetCode)

A.思路:我们将如何得到入口?

a.L=n*C-x(由这个公式我们可以找到交点)

B.因此由以上可以写得代码:


一、【环形链表1】. - 力扣(LeetCode)

2e1422846acd4fe7848af3928ec01a99.png
通过题目阅读,该环形链表指的是:原本单链表的尾节点的next指向链表中任意节点
d4df4d9ede6f49f391dbde72dae1a6b8.jpeg

因此,指向自己的情况也是会出现的。

A.思路

1.判断是否有环

1)如果是单链表,尾节点指向NULL,因此无环存在。
2)如果是环形链表,由于没有尾节点而陷入循环,因此需要找到一个在环中的节点。


a.因此难点在这里(使用快慢指针):如果用一个指针去遍历链表则会出现陷入死循环的情况,无法退出。

那如果用两个指针呢?
一个稍快的前进,一个稍慢的前进,较快的指针将会先进入这个环,在环中走。较慢的指针随后进入环,经过一段时间之后,他们会相遇。这时候找到了在环中的一个节点,因此便证明了存在环。
slow: 每次走一步;
fast:每次走两步;

60a094fab68e441dbcc6c525683f9860.jpeg

如图在某个时间他们会相遇。


B.我们可以通过以上思路写出代码:

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


而仅仅理解了知道了这个代码还不够。

C.笔试题

1、slow一次走一步,fast一次走两步一定会相遇吗?(一定会)

slow进环后,fast和slow的距离变化:

每次追击距离缩小1

假设slow进环时,fast和slow之间的距离是N

如图:

bc974af962b046faba688a06d4e4105a.jpeg

一次前进之后:

N`=N-2+1

=N-1

  N-2

  .......

   3

   2

   1

   0  距离为0则追上

2、slow一次走一步,fast一次走三步一定会相遇吗?(一定能追上)

slow进环后,fast和slow的距离变化:

每次追击距离缩小2

距离变化:

N: 偶数     奇数

     N-2       N-2 

     N-4       N-4

     .....        ......

     4            3

     2            1

     0           -1

为0则追上   距离为-1,则开始新一轮的追击,设环的周长是C,则新的距离为C-1,C-1为奇数则死循环,若C-1为偶数(相当于N为偶数)则能追上。

总结:

a.如果N是偶数直接就能追上。

b.如果N是奇数,C是奇数,第一轮错过,第二轮就能追上。

c.如果N是奇数,C是偶数,就永远追不上。(此条件不成立)

这个条件是不成立的如图:8ea3e4807cc84709907e3483dabd6fd5.jpeg

如图当slow进环时:slow与fast的距离为N,

在此之前:slow所走的路程为L,fast所走的路程为:n*C-N

而fast的速度是slow速度的1/2:

2L=n*C-N

偶数 =n*偶数-奇数(这是不成立的)

因此如果N是奇数,C是偶数,这个条件不成立。

3、slow一次走n步,fast一次走m步一定会相遇吗?(m>n>1)

这个问题同2

每次追击的距离缩小 m-n(>=1)的整数

若N%(m-n)==0就能追上

!=0则再看N%(C-x)==?---------同2的总结。

二、【环形链表2】(返回环的入口). - 力扣(LeetCode)

c8792378b77c4f8880cceb40e920473c.png

A.思路:我们将如何得到入口?

df76baaa5ecd4c45a5a0594ddc7b3050.jpeg

如图:

起点到如环的距离:L

入口点到相遇点:x

环的长度:C

从开始相遇时slow走的距离:L+x

从开始相遇时fast走的距离:L+n*C+x

而我们可知道:fast路程=slow路程*2

2*(L+X)=L+n*C+x

a.L=n*C-x(由这个公式我们可以找到交点)

解释:在slow和fast相遇时所在的节点B用meet指向,再由一个指针head从链表的开始开始走,head走L,meet走n*c-x,他们就会在A点相遇,s此时返回head/meet,则可以得到入口节点。

B.因此由以上可以写得代码:

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

本篇文章的内容到此就结束了,非常感谢大家的阅读,若有不足与改进之处,欢迎在评论区里指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值