数据结构练级之路【链表带环问题】

简介: 数据结构练级之路【链表带环问题】

一、链表带环问题的代码和几个经典的面试题(重点在于如何算入口点)

代码非常的简单,但是有几个关于带环问题的讲解就比较不好理解


1.有关链表是否带环的题目和代码


(较难且较经典)(有关链表带环的问题)(经典的引用了快慢指针的使用)(追击问题)

题目:给定一个链表,判断链表中是否有环。

意思:如果链表中有某一个结点,可以通过连续跟踪next指针再次到达,则链表中存在环,为了表示给定链表中的环,我们使用整数pos来表示链表尾链接到链表中的位置(索引从0开始),

如果pos的位置是-1.则在该链表中没有环,注意pos不作为参数进行传递,仅仅是为了标示链表的实际情况。

思路:使用快慢指针(slow和fast都从头结点开始,slow一次走一步,fast一次走两步,不带环fast就会为空,带环fast就会追上我的slow);


实现:


bool hasCycle(struct ListNode* head)//有环就返回true无环就返回false
{
  struct ListNode* fast = head;
  struct ListNode* slow = head;
  while (fast && fast->next)//这个就是一次走两步,此时就会涉及到一个奇偶的问题,所以两个条件都要进行判断
  {
    slow = slow->next;
    fast = fast->next->next;
    if (slow == fast)//这步就是表示我追击到了(此时就是可以表明这个链表是带环的链表)
    {
      return true;
    }
  }
  return false;
}

2.经典的带环问题1

问题:问为什么slow走一步,fast走两步最后一定可以相遇?


解答:因为假如fast在追击slow的时候(此时的fast已经入环了,然后假设此时它们之间的距离是N),因为此时的fast每次都比slow多走一步,所以此时的距离就会从N到N-1,这样一直走下去,N肯定可以变成0,所以肯定可以找到


3.经典带环问题2

问题:问假如fast此时不走两步而是走n步,此时还一定可以找到吗?

解答:答案首先是:不可以;原因:

假如此时的fast走的是3步,距离还是N,fast每次比slow多走2步,所以此时是N-2,N-4(所以就可以显然看出此时假如N是一个奇数就不能追到,只有当N是一个偶数的时候才可能追到),所以不一定可以追到,并且如果继续往下一圈走的时候,如果此时还是没有追到(那么此时的这个fast就不可能找到slow了);因为:假如此时的N是一个奇数,然后此时就会导致fast在slow的前面(如果当我的fast在slow的前面时,此时的fast和slow的距离就发生的大改变,从小变成了最大,因为此时fast在前,所以距离就变成了环的长度-1(C-1)),所以假如C-1是一个奇数就会导致N是奇数(那么此时就又是那个道理,N是奇数就追不到),只有当C-1(N)是一个偶数时,才有可能追上,所以关键追上与追不上就是取决去(环的长度是奇数还是偶数),但是还要注意这边是有一个减1的,所以环的大小是偶数就追不到,环的大小是一个奇数就可以找到


4.如何求环的入口点?(理论解答)

第一种方法:

环的入口点的思路:一个指针从相遇点开始走,一个指针从链表头结点开始走,它们会在环的入口点相遇

为什么是这样的呢?所以下面我们就来介绍一下为什么一个指针从相遇点开始走,一个指针从链表头结点开始走,它们会在环的入口点相遇呢?


由上述的思路我们此时假设:

从头结点到入环点的距离是:L

环的长度是:C

慢指针在环中走的距离为:X

走的圈数是:N

所以此时在追上到相遇的过程中

慢指针走的距离:L+X

快指针走的距离:L+X+C 而是 L+X+N*C

又因为快指针走的路程是慢指针的2倍

所以此时就可以得到一个等式:

2 * (L+X) = L+X+N * C

变形得到:L+X=N * C

变形得到:L=N * C-X

变形得到:L=(N-1)*C+C-X

所以此时通过这个表达式,此时就可以得到 L=C-X;因为此时的N-1可以看成是一个整数倍的圈数,就可以看成是在循环,其实还是从这个位置开始

所以就得到了 L=C-X; 所以我们就证明了这句话 :一个指针从相遇点开始走,一个指针从链表头结点开始走,它们最终会在环的入口点相遇。


下面是图示:


11.jpeg


11.jpeg


具体求入口点的代码:

struct ListNode* detectCycle(struct ListNode* head)
{
  struct ListNode* slow = head;
  struct ListNode* fast = head;
  while (fast && fast->next)
  {
    slow = slow->next;
    fast = fast->next->next;
    if (slow == fast)//这个条件会成立的话就表示我链表是有环的,并且此时追到了
    {
      struct ListNode* meet = slow;
      //此时的这个循环中的结论就是由我的公式证明出来的
      while (meet != head)
      {
        meet = meet->next;
        head = head->next;
      }
      return meet;
    }
  }
  return NULL;
}

第二种方法:

就是可以先算出这个环的相遇点,然后把这个点给断开,然后就可以非常巧妙的把这个判断环的相遇点的问题给转换成求交点的问题(但是代码实现起来优点困难)


二、总结:

以上就是有关链表带环的一系列问题,建议反复画图理解

相关文章
|
20天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
48 4
|
22天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
22天前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
20天前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
39 0
|
1月前
|
存储
[数据结构] -- 双向循环链表
[数据结构] -- 双向循环链表
23 0
|
1月前
|
存储
探索数据结构:便捷的双向链表
探索数据结构:便捷的双向链表
|
1月前
|
存储
探索数据结构:单链表的实践和应用
探索数据结构:单链表的实践和应用
|
5月前
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
5月前
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表
|
5月前
|
存储 算法 Java
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
56 2