当前位置:   article > 正文

经典的带环链表问题(链表补充)

经典的带环链表问题(链表补充)

环形链表1

运用快慢指针的方法,fast ,slow从头节点出发,快指针走两步,慢指针走一步,若有环,快指针先进环,后续如果慢指针和快指针相遇,则链表带环。转换成了追击问题。

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

思考:为什么一定会相遇,会不会错过,永远追不上?若快指针走三步,四步呢?

证明:假设链表就是有环,slow(1步)进环时,fast(两步)与slow的距离为N,追击过程中,每走一次,N都会-1,最后到0。本题的思想证明,距离为0就是追上了。

若fast走三步,同样假设slow进环时,fast与slow相差N,

fast追击slow过程中,距离变化一直-2,但是最后结果要注意,N为偶数时,最后变为0,N为奇数时,最后为-1.而当距离为-1时,两指针会错过,进行新一轮追击。这时假设环的长度为C。新的距离就变成C-1了,这是又要将C分为奇数,偶数进行讨论。

那么是否存在N是奇数且C是偶数的情况呢,

假设从出发位置到进环的位置相差L,slow进环时,fast已经走了x圈,且fast与slow相差N:

进环时:slow走的距离->L

fast走的距离->L+x*C+C-N

fast的距离应该为slow的三倍:3*L=L+x*C+C-N 

化简为:2*L=(x+1)*C-N  若要满足该等式,若C是偶数,N必须是偶数。若N是奇数,如果C是偶数,则(x+1)*偶数一定是偶数,偶数-奇数!=偶数。

所以上述条件不成立,故永远追不上的条件不成立。

结论:一定能追上。

N是偶数第一轮追上。N是奇数第一轮追不上,C是奇数,第二轮追上。

其他走四步等的条件证明过程类似。

环形链表2

本题相较于第一个环形链表题,多了返回节点位置的步骤,所以最初思路也是通过快慢指针,快慢指针相遇,则证明有环存在,然后将两指针相遇点记为meet,再继续走,此时头节点也开始移动,meet与head相遇点就是环的最初节点。

证明过程如下:

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

这种方法不容易想到,还有另外一种方法,将快慢指针相遇点newhead=meet->next,meet->next=NULL,此时从newhead开始,与原链表head通过相交链表的思路求解。

  1. struct ListNode {
  2. int val;
  3. struct ListNode *next;
  4. };
  5. typedef struct ListNode LN;
  6. struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
  7. LN*cur1=headA,*cur2=headB;
  8. int lenA=1,lenB=1;
  9. while(cur1){
  10. cur1=cur1->next;
  11. lenA++;
  12. }
  13. while(cur2){
  14. cur2=cur2->next;
  15. lenB++;
  16. }
  17. //尾节点不相同就没有相交
  18. if(cur1!=cur2){
  19. return NULL;
  20. }
  21. //假设法
  22. int gap=abs(lenA-lenB);
  23. LN* longlist = headA;
  24. LN* shortlist = headB;
  25. if(lenA<lenB){
  26. longlist=headB;
  27. shortlist=headA;
  28. }
  29. while(gap--){
  30. longlist=longlist->next;
  31. }
  32. while(longlist!=shortlist){
  33. longlist=longlist->next;
  34. shortlist=shortlist->next;
  35. }
  36. return longlist;
  37. }
  38. struct ListNode *detectCycle(struct ListNode *head) {
  39. LN*slow,*fast,*meet;
  40. slow=fast=head;
  41. while(fast && fast->next){
  42. slow=slow->next;
  43. fast=fast->next->next;
  44. if(slow==fast){
  45. meet=slow;
  46. LN* newhead=meet->next;
  47. meet->next=NULL;
  48. return getIntersectionNode(head,newhead);
  49. }
  50. }
  51. return NULL;
  52. }

本节内容到此结束,感谢各位友友对小编的支持!!!

觉得本文章有用的话留下三连和评论吧!!!

咱们下期再见!!!

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

闽ICP备14008679号