浅尝链表带环问题(LeetCode:141,142 环形链表)

本文详细介绍了如何解决链表带环问题,包括判断链表是否带环以及找到入环的第一个节点。通过双指针法,即快慢指针,来有效地解决这类问题。代码实现简洁明了,并对相关思路进行了深入分析。后续文章将探讨快慢指针移动的原理。
摘要由CSDN通过智能技术生成

目录

前言

一,问题分析

1.1环形链表 I

1.2 环形链表II

二,是否带环分析 

2.1推荐使用“二指针”

                    为什么不使用“一指针”

2.2思路分析

2.3代码实现

三,带环 - 入环节点 

2.1思路分析

2.2代码实现 


前言

小伙伴们大家好啊!今天为大家带来一篇有关链表带环问题的文章,众所周知,链表带环问题在单链表的应用中相对来说,是比较复杂的一类问题,所以今天小编就带大家一起看看吧!

一,问题分析

这次我们通过两个环形链表的题目,来了解一下,带环链表的特点。

1.1环形链表 I

如上图所示,题目中说明,我们需要判断一个链表是否带环,然后带环的链表的要求是:链表中一定有一个节点,可以通过连续跟踪 next 指针再次到达。

也就是说,如果带环的话,那么某个节点的指针一直通过 next 往后移动,那么一定会再次到达那个节点。

1.2 环形链表II

那么类似的第二道题是如上描述的,和第一道题类似,同样都需要判断是否带环,但是这个题附加的条件是如果带环,则需要返回开始入环的。 

所以,我们看到,其实对于带环问题,简单的方面主要就是判断是否带环,如果带环的话,则返回入环的第一个节点。

二,是否带环分析 

那么根据上面两个题目的要求,我们知道,对于链表带环,首先就是需要判断是否带环也就是第一个题目。

2.1推荐使用“二指针”

                    为什么不使用“一指针”

我们知道,因为单链表涉及到的很多问题一个指针是不能解决的,所以这里同样的,我们也用两个指针,但是这里用两个指针的主要原因是:

一个指针不能实现。因为我们不知道链表有几个节点,假设该链表带环,那么我们就需要有一个东西记住了该节点第一次出现的位置,然后第二次出现的时候,我们将这两个节点的位置比较了一下,发现是一样的,这就说明了,确实是带环的。

但是如果只用一个指针的话,那么我们就需要每次就记录一下访问过的节点的地址,然后有一个指针从头节点一直移动,我们需要判断的就是该指针如果第二次出现在同样的地址的话,说明是带环的,但是这是不现实的,因为我们不知道有多少个节点(就算是计算也是比较繁琐的),即使我们知道了,难道我们需要将这些节点的每个地址都记录下来吗?

显然这是不现实的,所以这里我们需要用两个指针。

2.2思路分析

那么既然用两个指针实现的话,思路就相对来说比较简单了。

 如上图所示,两个指针 fast 和slow一开始都是指向头节点的。然后这里我们一般的做法是快指针 fast 一次移动两个位置,然后 slow 一次移动一个位置,这样去移动是有一定的规律的(这个在后面的文章中我们会有证明)。那么不这样移动可以实现判断带环问题吗?可以的,但不是一定能判断,而上面那种做法是一定可以实现的,所以一般我们用上面那种做法。

那么我们确定了快指针 fast 一次移动两个位置,而慢指针 slow 一次只移动一个位置。如下图所示:那么对于当前链表,移动三次之后,两指针处于同一个位置,此时就如开头说得那样,如果两个指针的地址再次一样的话,说明是带环的,否则不可能两指针地址再次相同。

 好的,那么废话不多说,直接上代码。

2.3代码实现

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

 其实相对来说,代码实现是比较简单的,主要的是我们需要理解,如果链表带环的话,什么条件下,说明链表带环了,怎么样去实现?那么如果小伙伴们看完上面的解析之后,还觉得不是很理解,可以关注后续文章:为什么fast一次走两步,slow一次走一步?

三,带环 - 入环节点 

那么经过上面我们的分析之后,相信大家对于是否带环也有了自己的想法。那么我们接下来解决一下带环的链表,其入环的节点的问题。也就是上面环形链表的第二题,求出第一次入环的第一个节点。

2.1思路分析

因为这个题是在第一题的基础上实现的,所以我们不做过多解释,直接进入主题。

这里我们通过实践发现了一个规律:如果链表带环的话,我们首先用双指针让其相遇,在第一次相遇的地方设置一个指针 meet ,然后将链表的头指针 head 和 meet 指针一起移动,那么这两个指针一定会在入环的地方相遇。此时返回 meet 指针即可。

tips:对于该规律,以及上面的为什么fast一次走两步,而slow一走一步。后续小编会为大家带来一篇详解。

在这两个题目中,大家只需要能够理解这样做可以做出来题目就可以了。

2.2代码实现 

那么因为思路我们在第一题中讲述的很详细,这里我们不做过多解释。

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

好的,那么本文到此就结束啦,如果大家还有问题的话,还请指正鸭!

                                      

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值