当前位置:   article > 正文

链表经典面试题--链表修至圆满

链表经典面试题--链表修至圆满

目录

1.环形链表

a.为什么一定会相遇,有没有可能会错过,永远追不上?请证明

 b.slow一次走1步,fast走3步  4步  5步  n步还一定追得上吗  请证明

2.环形链表2

3.随机链表的复制


1.环形链表

141. 环形链表 - 力扣(LeetCode)

 思路:

快慢指针,慢指针走一步,快指针走两步

进环以后快指针开始追击慢指针

当快指针能追上慢指针就证明链表带环

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

面试问题:

a.为什么一定会相遇,有没有可能会错过,永远追不上?请证明

 

 假设slow进环时,fast跟slow距离时N,fast追击slow的过程中距离变化如下:

N

N-1

N-2

...

2

1

0

 每追击一次,距离缩小1,距离为0就是追上了

 b.slow一次走1步,fast走3步  4步  5步  n步还一定追得上吗  请证明

假设slow进环时,fast跟slow距离时N,

fast追击slow得过程只距离变化如下:

偶数        奇数

N                N

N-2             N-2

N-4             N-4

...                ....

4                   3

2                   1

0                   -1

追上了          错过了---->进行新得一轮追击,距离变成C-1(假设C是环得长度)

                        两种情况:1.C-1是偶数  2.C-1是奇数

 总结:

1.N是偶数,第一轮就追上了

2.N是奇数,第一轮追击会错过,距离变成C-1

        a、如果C-1是偶数下一轮就追上了

        b、如果C-1是奇数,那么就永远追不上

结论:如果同时存在N是奇数且C是偶数,那么就永远追不上

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

 假设slow进环时,fast跟slow距离时N,

slow走的距离是:L

slow进环时,假设fast已经在环里面转了x圈

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

 假设fast走的距离是slow的3倍

3*L = L + x*C + C - N

||

2*L = (x+1)*C + C + N

||

偶数=(x+1)*偶数 - 奇数

 由此,N是1奇数时,C也是奇数;N是偶数是,C也是偶数

只有奇数-奇数才能等于偶数

(x+1)*偶数一定等于偶数

所以,N是奇数且C是偶数不能同时存在,永远追不上的条件不成立

结论:一定能追上

N是偶数第一轮就追上了

N是奇数第一轮追不上,C-1是偶数第二轮就追上了

2.环形链表2

142. 环形链表 II - 力扣(LeetCode)

 与上面一样

相遇时:slow走的路程:L+N; fast走的路程:L+x*C  + N

假设fast走的路程时slow2倍

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

||

L+N=x*C

||

L=x*C-N

||

L=(x-1)C + C - N

 

 由此,slow走到开始入环的第一个节点时恰好是head走到开始入环的第一个节点处

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

3.随机链表的复制

138. 随机链表的复制 - 力扣(LeetCode) 

 

 思路:

把每个拷贝节点连接到原节点的后面

控制random

把拷贝节点拿下来尾插成新链表,恢复原链表

  1. struct Node* copyRandomList(struct Node* head) {
  2. //把每个拷贝节点连接到原节点的后面
  3. struct Node* cur=head;
  4. while(cur)
  5. {
  6. struct Node* copy=(struct Node*)malloc(sizeof(struct Node));
  7. copy->val=cur->val;
  8. copy->next=cur->next;
  9. cur->next=copy;
  10. cur=copy->next;
  11. }
  12. //控制random
  13. cur=head;
  14. while(cur)
  15. {
  16. struct Node* copy = cur->next;//拷贝节点已经连接到原节点的后面
  17. if(cur->random==NULL)
  18. {
  19. copy->random=NULL;
  20. }
  21. else
  22. {
  23. copy->random=cur->random->next;//复制链表random指向原链表random指向的节点的拷贝节点
  24. //copy->random=cur->random;//错误,不能指向原链表的节点
  25. }
  26. cur=copy->next;//继续往下遍历
  27. }
  28. //把拷贝节点拿下来尾插成新链表,恢复原链表
  29. struct Node* copyhead=NULL;//新链表头节点
  30. struct Node* copytail=NULL;//新链表尾节点
  31. cur=head;
  32. while(cur)
  33. {
  34. struct Node* copy=cur->next;
  35. struct Node* next=copy->next;
  36. if(copytail==NULL)
  37. {
  38. copyhead=copytail=copy;
  39. }
  40. else
  41. {
  42. copytail->next=copy;
  43. copytail=copytail->next;
  44. }
  45. cur->next=next;//恢复原链表
  46. cur=next;
  47. }
  48. return copyhead;
  49. }

感谢观看,再见

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

闽ICP备14008679号