当前位置:   article > 正文

【数据结构】C语言算法练习题——利用“快慢指针”去判断一个链表中是否带环_快慢指针判断链表是否有环

快慢指针判断链表是否有环

题目链接:

力扣https://leetcode.cn/problems/linked-list-cycle/submissions/

解题思路:

1. 带环链表不能遍历,否则会造成死循环

2. 定义俩个快慢指针,慢指针每次向后走一步,快指针每次向后走俩步。即快慢指针相差一步。

所以如果一个链表中存在环结构,

则快指针一定比慢指针先进入环结构,随着快指针进入环内运动循环,慢指针最终也会进入环内。

因为快慢指针均进入了一个环结构,所以不会遇到 NULL 指针,一直在循环。

这会使快慢指针最终会相遇,即指向的地址相同

而如果这个 单链表中 不存在环结构,则快指针最终会遇到 NULL 指针结束循环

这实际上是根据带环链表的结构特点去解题

3. 不带环结构的单链表需要考虑其结点的个数是奇数个还是偶数个

4. 【思考】:为什么快慢指针在环结构内最终一定会相遇?

为什么快指针每次走两步,慢指针走一步可以?

假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。

当慢指针刚进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。

此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况,

因此:在满指针走到一圈之前,

快指针肯定是可以追上慢指针的,即相遇

快指针一次走3步,走4步,...n步行吗?

不一定可行,即慢指针可能追得上快指针,也可能追不上

假设快指针一次走三步,慢指针一次走一步:

因为不知道环的长度是奇数还是偶数,如果环的长度是偶数,则最终会相遇,而如果环的长度为奇数,则会追不上

距离是 -1 意味着:快慢指针之间的距离 C(环的长度 )- 1

所以当进入新的一次带环结构循环时,如果C - 1 为奇数则永远追不上,如果C - 1 为偶数,则会在

接下来的几次带环结构里的循环追上

参考代码:

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * struct ListNode *next;
  6. * };
  7. */
  8. bool hasCycle(struct ListNode *head)
  9. {
  10. struct ListNode *fast , *slow;
  11. slow = head;
  12. fast = head;
  13. while (fast && fast->next)//不带环结构的单链表的结点个数分奇数个和偶数个;
  14. //存在偶数个结点时是 fast 走到 NULL
  15. //存在奇数个结点时是 fast->next 走到 NULL
  16. {
  17. slow = slow->next;
  18. fast = fast->next->next;//比慢指针多走一步,每次向后行走俩步
  19. if (slow == fast)
  20. {
  21. return true;
  22. }
  23. }
  24. return false;
  25. }

【题目变式】:

力扣icon-default.png?t=M4ADhttps://leetcode.cn/problems/linked-list-cycle-ii/description/

解题思路:

要想找到链表开始入环的第一个结点,

设入环前的距离为 L ,假设链表中带环,所以当快慢指针在环内相遇时,设慢指针从开始入环处的

第一个结点开始到快慢指针相遇时 慢指针走过的距离为 X 

注意:

进入环内快指针追上慢指针所走过的距离不会超过环的长度

其理由是:

快指针每次走俩步,而慢指针每次走一步,它们之间相差一步,即它们不像相差3步或俩步一样,

可能会错过,

假设慢指针已经走了一圈的长度没有遇到快指针,

因为每次快指针都比慢指针多走一步,所以此时快指针已经走了俩圈,

而且因为每次都相差一步,所以不会跳过慢指针,即不可能遇不到已经走了一圈的慢指针

即要么快慢指针要么遇不到,要么遇到就是在一圈之内

参考代码:

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * struct ListNode *next;
  6. * };
  7. */
  8. struct ListNode *detectCycle(struct ListNode *head)
  9. {
  10. struct ListNode *slow,*fast;
  11. slow = fast = head;
  12. while (fast && fast->next)
  13. {
  14. slow = slow->next;
  15. fast = fast->next->next;
  16. if (slow == fast)
  17. {
  18. struct ListNode *meet = slow;
  19. while (meet != head)
  20. {
  21. meet = meet->next;
  22. head = head->next;//meet与head同时向后走一步,注意与前面快慢指针所走步数的不同
  23. }
  24. return meet;
  25. }
  26. }
  27. return NULL;
  28. }

 

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/895289
推荐阅读
相关标签
  

闽ICP备14008679号