leetcode 环形链表Ⅰ&Ⅱ

1.环形链表Ⅰ

1.1 题目描述

本题链接来自 leetcode

image-20211108230050100

示例

image-20211108230219949

进阶和提示:

image-20211108230240515

image-20211108230247235

1.1.1 接口函数

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    
}

1.2 大致框架

1.2.1 想法思路

先要搞清楚什么是带环链表,即原链表的尾可能指向任何一个包含自己的节点

方法是用快慢指针,只要是一个环的话,只要有一个快指针和有一个慢指针,总会在某一个点相遇

1.2.2 具体步骤

实现一个快慢指针,放入循环,只要相等就说明是环

  while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)
        return true;
    }

1.3 整体实现

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;
}

image-20211109220719587

小结:

这道题只是一个初级阶段,所以解决起来很简单

但是面对下面三个问题你会如何解答?

image-20211110231326444

  1. 不会当slow进入环之后,本质上就是一个追及问题,fast与slow距离应该是越走越小
    image-20211110232019462
  2. 不一定,本质上和第一题道理逻辑是一样的
    总结一下就是在fast一次走三步的情况下, 如果slow进环时,slow跟fast差距N是奇数,且环的长度时是偶数,那么就永远也追不上

所以这个题目是不能乱设置fast的速度的

  1. image-20211111160258048image-20211111160324588

由于快指针走的路程是慢指针的二倍,所以有一个等式:
2 ∗ ( L + X ) = L + C + X 2*(L+X)=L+C+X 2L+X)=L+C+X
然而这样的推论是错误的,因为我们忽略了fast指针的可能性

没错slow确实只会走一圈以内的路程,fast就会追上slow,所以slow走的距离是L+X

然而fast并不一定是只走了一圈,完全可能在里面走了N圈所以快指针应该是走了
2 ∗ ( L + X ) = L + N ∗ C + X 2*(L+X)=L+N*C+X 2L+X)=L+NC+X
所以化简等式之后应该是
L = N ∗ C − X L=N*C-X L=NCX {N*C-X}

由之前的结论我们来做下面来一道升级版的题目就会有思路

2. 环形链表Ⅱ

本题链接来自leetcode

2.1 题目描述

image-20211111163440884

示例

image-20211111164122045

进阶和提示

image-20211111164220795

2.1.1 接口函数

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    
}

2.2 方法一

方法一的想法继承的是之前的第三个问题的想法,本质上来说,方法难想,但是代码简单

2.2.1 具体步骤

由于之前给出的公式
L = N ∗ C − X L=N*C-X L=NCX {N*C-X}
所以由推论可以证明,假如我把相遇点fast指针位置叫做meet,还有一个头指针head,两个指针一个从head走L,一个从meet走会走N*C-X,他们会在入口点相遇,正好以此求出入口点的位置

2.2.2 整体实现

 struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* slow=head,*fast=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)
        {
            //相遇
             struct ListNode*meet=fast;
             //通过推论证明,一个指针
             while(meet!=head)
            {
                meet=meet->next;
                head=head->next;
            }
            return meet;
        }
    }
    return NULL;
}

image-20211111165835118

2. 3方法二

相对于方法一来说方法二想法简单但是代码复杂

2.3.1 想法和思路

先快慢指针相遇,然后我们把相遇的点置空,创建一个newhead节点,然后和head一起走的话就转变成之前做过的相交问题了,以此找出交点所在就是我们要求的

链表的相交问题

image-20211111171957391

这里就不在这里写这个方法了

小结:

环形链表的这道题主要还是比较考验数学思想的一道题目,有这样一个想法很重要

如果老铁们有收获的话,希望给个一键三连哦,谢谢

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

言之命至9012

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

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

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

打赏作者

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

抵扣说明:

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

余额充值