当前位置:   article > 正文

链表OJ题之环形链表

链表OJ题之环形链表
  • 带环链表:尾节点的next指向链表中的任意点(甚至可能指向它自己)

思考 

接下来有几个问题需要我们来思考一下:

Q1

slow一次走1步,fast一次走2步,他们一定会相遇吗?(slow在走满一圈之前)

假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。如果是最差情况:两个指针之间的距离刚好就是环的长度,那么当慢指针刚进环时,就和快指针相遇了。若两者相距N,如图所示,此时,两个指针每移动一次,之间距离缩小一步,因为是整数,所以总会缩小到0。

所以它们一定会相遇! 

Q2

slow一次走1步,fast一次走3步,他们一定会相遇吗?

  • 设N是slow开始入环,fast的最初开始追击的距离,C是环的长度。 
  • 如果N是偶数第一轮就直接追上了。
  • 如果N是奇数,C是奇数,C-1是偶数,第二轮也追上了。
  • 如果N是奇数,C是偶数,C-1是奇数,永远追不上。

 

若第一轮没有追上,那么它们之间就差了-1,fast在前面,那么我们可以看C-1的奇偶,如果C-1是偶数,那么

 而如果C-1是个奇数,那么

请独立思考 

如果N是奇数,C是偶数,那么就追不上。这个条件是否成立?请证明!

其实这个条件是不存在的,不可能会出现这种情况!

 经过分析我们可以知道,当N是奇数,C是偶数的时候,这个式子不成立,所以这种情况一定不存在!所以 slow一次走1步,fast一次走3步,他们一定会相遇!

Q3

slow一次走n步,fast一次走m步,他们一定会相遇吗?(m>n>1) 

这个和Q2有相似之处。

  • 如果  N%(m-n) == 0 第一圈就直接追上了。
  • 如果  N%(m-n) == x 第一圈也追不上了。
  • 如果  (C-x)%(m-n) == 0 第二圈就追上了。
  • 如果  (C-x)%(m-n)  != 0   永远追不上了。
     

Q4

请证明:

让一个指针slow从链表起始位置开始遍历链表,同时让一个指针fast从判环时相遇点的位置开始绕环运行,注意slow每次走1步,fast每次走1步,最终肯定会在入口点的位置相遇。 

速度是二倍关系,那么相同时间里,fast的路程也是slow路程的2倍 

  

得证。

同时这个思路也可以用在Q2的独立思考题里。

通过这个结论,我们就可以找到入口点了!!

 

例题

环形链表1

给你一个链表的头节点 head ,判断链表中是否有环。

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

如果链表中存在环 ,则返回 true 。 否则,返回 false 。 

 

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

思路:快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置开始往后走,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。 

  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 *faster=head;
  11. struct ListNode *slow=head;
  12. //一起走faster走2步 slow走1步--保持相对速度
  13. while(faster && slow && faster->next)
  14. {
  15. faster=faster->next->next;
  16. slow=slow->next;
  17. if(slow == faster)
  18. {
  19. return true;
  20. }
  21. }
  22. return false;
  23. }

 环形链表2

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

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

不允许修改 链表。

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

思路:用Q4的结论: 

让一个指针slow从链表起始位置开始遍历链表,同时让一个指针fast从判环时相遇点的位置开始绕环运行,注意slow每次走1步,fast每次走1步,最终肯定会在入口点的位置相遇。 

  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=head;
  11. struct ListNode *fast=head;
  12. struct ListNode *meet=NULL;
  13. while(fast && fast->next)
  14. {
  15. fast=fast->next->next;
  16. slow=slow->next;
  17. if(fast == slow)
  18. {
  19. slow=head;
  20. while(fast != slow)
  21. {
  22. slow=slow->next;
  23. fast=fast->next;
  24. }
  25. return fast;
  26. }
  27. }
  28. return NULL;
  29. }

环形链表到相交链表的转化 

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

闽ICP备14008679号