当前位置:   article > 正文

有环链表环的问题_链表用环的空间复杂度

链表用环的空间复杂度

有关于链表,我们总会遇到关于其的各类问题,像反转链表,双向链表,有环链表等,今天,我们就有环链表展开细说。


1.判断链表有环

如果有一个单向链表,且链表中可能出现“环”,那么,该如何用程序来判断该链表是否为有环链表?

13703adbb22d41bc8e128b975445ca23.jpg

方法一:也是最简单粗暴的方法,从头节点开始,依次遍历单链表中的每一个节点。每遍历一次新节点,就与之前所有节点进行比较,如果某个节点被遍历两次,则为有环。(时间复杂度为O(n²),空间复杂度为O(1))。

方法二:创建一个哈希表,以节点的id为key值的哈希表,存储曾经便利过的节点,在依次遍历整个链表,如果遍历的节点为新节点,那就记录在哈希表,当遍历发现在哈希表内部遍历过,证明链表有环。(使用了哈希表作为额外缓存,该解法时间复杂度为O(n),空间复杂度为O(n))。

d0b36a4d0c98443a84809e2bd9e9df03.jpg

 方法三:利用双指针法.创建两个指针p1,p2使它们同时指向链表的头节点,使p1 = head -> next; p2 = head -> next ->next;(即使p1速度为1,p2速度为2)。

1.p1,p2指向节点5

945bcf0ebf5648928d2f4773c17eb742.jpg

 2.p1指向3,p2指向7

1334c44d6d0a45ce936f4eb38f436680.jpg

 3.p1保持速度1,p2保持速度2,如果有环,则速度快的一定会追上速度慢的,当p1 == p2时证明了链表有环

2855ccaae6db40c68c0cbec7ab35c8a2.jpg

下面为部分代码实现:

  1. //部分代码
  2. bool isCycle(ListNode *Head) {
  3. ListNode* p1 = head;//设置双指针指向头节点
  4. ListNode* p2 = head;
  5. while (p2 != NULL && p2->next != NULL)
  6. {
  7. p1 = p1->next;//设置p1速度为1
  8. p2 = p2->next->next;//设置p2速度为2
  9. if (p1 == p2)
  10. {
  11. return ture;//p1 == p2表示两指针相遇,为有环链表
  12. }
  13. }
  14. return false;//双指针不相遇,不是有环链表
  15. }

2.获取有环链表的环长以及入环点

 1.求有环链表的环长

当两个指针首次相遇,证明链表有环的时候,让两个指针从相遇点继续循环前进,统计前进次数,直到第二次相遇,此时统计出来的次数就是环长,因为p1速度为1,p2速度为2,则再次相遇的时候,p2比p1多走了一圈,统计出来前进的次数就为环长。

  1. int isCycle(ListNode *Head) {
  2. ListNode* p1 = head;
  3. ListNode* p2 = head;
  4. static int count = 0;//记录前进次数
  5. while (p2 != NULL && p2->next != NULL)//第一个循环先使得p1 、 p2 处于第一次相遇的位置
  6. {
  7. p1 = p1->next;
  8. p2 = p2->next->next;
  9. if (p1 == p2)
  10. {
  11. break;
  12. }
  13. }
  14. while (p2 != NULL && p2->next != NULL)
  15. {
  16. p1 = p1->next;
  17. p2 = p2->next;
  18. count++;
  19. if (p1 == p2)
  20. {
  21. break;//第二次相遇时终止循环
  22. }
  23. }
  24. return count;//将记录的前进次数返回
  25. }

 2.求有环链表的入环点

假设从链表头节点到入环点的距离是D,从入环点到两个指针首次相遇点的距离为S1, 从首次相遇点到入环点的距离为S2。

分析:当第一次相遇时,指针P1一次只走一步,  所走的距离为D + S1。指针P2一次走2步, 多走了n(n >= 1) 圈, 所以走的距离为D + S1 + n(S1 + S2)。

则2(D + S1) = D + S1 + n(S1 + S2)

则D = (n - 1)(S1 + S2) + S2

也就是说,从链表头节点到入环点的距离,等于从首次相遇点绕环n - 1 圈在回到入环点的距离

则此时, 把其中任意一个指针放回到头节点,并且保持速度都为1,则他们最终相遇的节点就是入环点。

2c30785fe5724979af27b421e0e4dfaf.jpeg

 

  1. ListNode* detectCycle(ListNode* head) {
  2. ListNode* p = head, * q = head;
  3. while (q && q->next) {//当q 与 q 的下一个节点不为空则执行循环
  4. p = p->next;
  5. q = q->next->next;
  6. if (q == p) break;//到达首次相遇点时停止
  7. }
  8. if (q == NULL || q->next == NULL) return NULL;
  9. p = head;
  10. while (p != q) {//直到再次相遇时停止循环
  11. p = p->next;
  12. q = q->next;
  13. }
  14. return p;//返回p或q节点都是入环节点
  15. }

OK,有环链表的问题今天就介绍到这里啦,主要对有环链表的入环点,环长,以及判断是否存在环(前两个例子我就不敲了,理解就好)希望对你有所帮助,学无止境,我们一起加油一起学习,也祝各位小伙伴们学业有成,早日进入自己心仪的大厂! 

192ccf7267a04abd89ef7d2db5f239fe.jpeg

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/681904
推荐阅读
相关标签
  

闽ICP备14008679号