数据结构—Leetcode环形链表1、2解法及其结论过程推导

在这里插入图片描述

山川如环,连绵不绝;人生如秀,周而往复。

1. 环形链表

1.1 Leetcode环形链表1

题目:https://leetcode.cn/problems/linked-list-cycle/
在这里插入图片描述

分析:

  阅读题目,可以知道题目是想要我们判断该链表之中是否含有环,所以我们只需要知道怎么样可以判断是否有环即可。

   可以看到普通的链表中有空指针,而带环的链表中没有空指针。所以可以从中出发,初始化一个当指针指向head,依次遍历链表中的各个节点,当为指针指向NULL的时候结束。但是此时带环链表中的指针会陷入循环,所以我们考虑再引入一个指针,用快慢指针在这里插入图片描述

  快慢指针指的是设定两个指针,其中快的指针的移动速度是慢的指针的移动速度的两倍。
  快慢指针方法主要用来解决两类问题,即“判断一个链表是否为循环链表”以及“寻找一个有序链表的中位数”

解题:

   使用快慢指针,初始化slow和fast都指向head。slow每次向后走一步,fast每次向后走两步,如果fast走到了NULL就说明该链表是普通链表,输出false。
  如果为环形链表,则fast一定会比slow先进入环中且不断的循环,等slow也进入环中,两者直接相遇或者fast开始追击slow,因为slow比fast慢一步,所以fast一定会追上slow,当slow==fast成立,输出true。
在这里插入图片描述
在这里插入图片描述

bool hasCycle(struct ListNode *head) {
    struct ListNode*fast;
    struct ListNode*slow;
    fast=slow=head;

    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;

        if(fast==slow)
        return true;
    }
    return false;
}

1.2.1 slow走一步,fast走两步,一定会相遇?

  由上面的分析可以得到答案是: 一定的

  假设链表带环,那么两个指针最后都会进入环,快指针先进环,慢指针后进环。
  当慢指针刚进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况。
  因此:在满指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。
在这里插入图片描述

1.2.2 进阶:若slow走一步,fast走n步(n>=3),是否会相遇?

不同与上面,答案: 不一定

  和上面的假设一样,这次让快指针走三步,慢指针走一步,两次指针每移动一步,之间的距离就缩小两步。但是和上面不同,如果快指针和慢指针的距离是一的话,快指针就会直接跳过慢指针,造成快慢指针的错过。
  所以这里要对fast和slow之间的距离N进行讨论。在这里插入图片描述

如果N为偶数,则可以直接相遇;如果N为奇数,则又需要进入新的一轮追击。
在这里插入图片描述

当fast走n步(n>=3)也是一样的步骤。

1.2 Leetcode环形链表2

题目:
https://leetcode.cn/problems/linked-list-cycle-ii/
在这里插入图片描述

在这里会有一个结论:
  当一个指针从相遇点走,一个指针从起始点走,会在入口点相遇。

  有了结论我们就可以很快的找到解题的方法了,我们同样引入快慢指针,先判断是否有环,如果没有环就可以直接返回NULL;
  进入环了之后我们开始快慢指针的追击,当快慢指针相遇的时候,我们就使用我们的结论,初始化两个指针分别用来标记相遇点和链表的起始点当一个指针从相遇点走,一个指针从起始点走,会在入口点相遇,判断它们如果相等的话,那么就说明该相遇点是我们所需要的入口点
在这里插入图片描述

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *fast ,*slow;
    fast=slow=head;

    while(fast&&fast->next)
    {
        
        slow=slow->next;
        fast=fast->next->next;
    
        if(fast==slow)
        {
        struct ListNode*meet,*start;
        meet=fast;
        start=head;

        while(meet!=start)
        {
            meet=meet->next;
            start=start->next;
        }

        return meet;
        }
    }
    return NULL;
}

1.2.1 进阶:怎么推出链表中双指针起始点、入口点、相遇点之间的关系?

结论:一个指针从相遇点走,一个指针从起始点走,会在入口点相遇        L=(n-1)*C+C-X

  证明:假设起始点到入口点的距离是L,入口点到相遇点的距离是X,环的距离是C;因为fast比slow每次都快一步,所以fast走的距离是slow的两倍,fast和slow相遇后停止。此时,slow的距离是L+X,fast的距离是L+C+X。由两倍关系可以得:2(L+X)=L+C+X 推出-> L=C-X
这里是引用

注意:

  这些情况都是L和C差不多长,如果L比C长很多的话,结论就不对了。
  在上面的基础上我们将fast指针走的C乘以一个n,即可推出通法L=(n-1)*C+C-X在这里插入图片描述

这些就是有关数据结构中环形链表的简单介绍了😉
如有错误❌望指正,最后祝大家学习进步✊天天开心✨🎉

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鳄鱼麻薯球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值