带环链表(数据结构)

本文介绍了带环链表的概念,通过实例演示如何使用快慢指针检测链表中的环,并提供了LeetCode中的相关问题解析。通过分析环长和节点移动的关系,展示了如何找到环的第一个节点。
摘要由CSDN通过智能技术生成

1. 带环链表是什么?

        在链表数据结构中,有时会出现环形的结构。 这种环形的链表称为带环链表。
        以下图示便于大家理解,刚使用画图工具,还不太了解。

        只了解其形但却不了解其内在是远远不够的。接下来,我们将通过例题来进一步了解带环链表。

2. 链表存在问题 (. - 力扣(LeetCode)

题目一:

        给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

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

不允许修改 链表。

示例 1:

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

示例 2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。

        初看这道题是不是一脸懵,不知道该如何下手,你可能会想到要用双指针,然后可能就不知道该怎么做了,有思路,但思路不多,不过,能想到这就已经很不错了。好了,现在来公布一下解题方法吧,那就是需要用到快慢指针,怎么样,是不是和你想到的方法一样呢?没想到也没关系,毕竟你可能是第一次见,这题会了也可以接着看下去,就当巩固一遍了。

        好的,废话不多说,我们来看一下解题方法。

具体思路如下:

        我们可以先定义两个指针,一颗快指针fast,一个慢指针slow。快指针一次走两步,慢指针一次走一步,这样当快指针进环后,慢指针还在环外。当慢指针进环后,快指针已在环里走了一会了,由于环没有出口,快指针的速度比慢指针的速度快,那么快指针迟早会追上慢指针,一但快指针追上慢指针,即证明有环。

2.1 解法

解题代码如下:

1.  class Solution {
2.  public:
3.      bool hasCycle(ListNode *head) {
4.          struct ListNode* fast = head,* slow = head;
5.          while(fast && fast->next)
6.          {
7.              slow = slow->next;
8.              fast = fast->next->next;
9.              if(fast==slow)
10.             {
11.                 return true;
12.             }
13.         }
14.         return false;
15.    }
16. };

        不知道聪明的你是否能看懂呢,我想应该是可以的。看不懂也没关系,现在我们来共同看一下这个代码。

        首先,定义两个指针变量,一快一慢,这自然不必多说。然后就是下面这个循环体了,思路我们应该都清楚了,下面的代码也很简单,那么就来解释一下这个循环体的条件吧,由于快指针比慢指针走得快,假如这是一个无环的链表,那么理应是快指针先走到链表的末尾,这时候快指针已便历了链表,再走就为空了,这显然不是我们想看到的,所以当fast为空时,就要跳出循环了,又因为·fast一次走两步,故fast->next也不可为空,总结一下,就是二者需同时为真,程序才会运行下去,否则就跳出循环。

2.2 讨论

        上面快指针比慢指针一次多走一步,故若链表有环,就一定会相遇。那么如果多走两步,三步,四步呢,n步呢?请证明。是否也一定会相遇呢?请注意,接下来讨论的问题建立在链表有环的基础上。

环长为x

        假设slow刚进环时slow和fast的相对位置如图所示,设环长为x,fast还有c长度追上slow。

        现在讨论,fast比slow多走两步,可知,当c为偶数时一定可以追上,若c为奇数呢?

        那么一定会有个时间节点,fast位于slow前面一个位置,此时相对位移为x-1,若x-1为偶数,也必追上,则x为奇数 ,若x-1为奇数,则永远追不上!

那么是否会存在c为奇数,x为偶数的情况吗?

        假设未进环之前的长度为L。

        则当slow刚进环时走过路程为L

       fast走过路程为L+nx-c(n为fast在环内转的次数)

        则可得: 2L = nx-c

        则可知:nx-c为偶数,若x为偶数,则c必为偶数,显然不符合条件,故这种条件不存在。

即一定会相遇,无非是时间关系。

3. 环形列表二(. - 力扣(LeetCode)

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

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

不允许修改 链表。

示例 1:

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

示例 2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

提示:

  • 链表中节点的数目范围在范围 [0, 104] 内
  • -105 <= Node.val <= 105
  • pos 的值为 -1 或者链表中的一个有效索引

进阶:你是否可以使用 O(1) 空间解决此题?

 3.1 解法

解题代码如下:

1.  class Solution {
2.  public:
3.      ListNode *detectCycle(ListNode *head) {
4.          struct ListNode* fast = head,*slow = head;
5.          while(fast&&fast->next)
6.          {
7.              fast=fast->next->next;
8.              slow = slow->next;
9.              if(slow == fast)
10.             {
11.                 struct ListNode*meet = slow;
12.                 while(meet != head)
13.                 {
14.                     meet = meet->next;
15.                     head = head->next;
16.                 }
17.                 return meet;
18.             }
19.         }
20.         return NULL;
21.     }
22. };

下面照例来解释一下代码。

        首先,依旧是判断是否有环,然后就是找到入环的第一个节点。如图所示,设fast和slow相遇时,距第一个入环节点为C,则有如下关系:

        2(L+C) = L+C+nx

        即L = nx-C

        这时将引入另一个指针meet,从头节点开始,当其走L时,slow也已走了有效的剩下路程,这时无论n为何值都不影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值