• 【C++】顺序表 链表 栈练习题第三弹来啦(每日小细节008)


    我们前几天已经学过了线性表:顺序表,链表和栈,但是只有理论知识是绝对不够的,我给大家找了一些很经典的题目,一定要做到立马有思路哦

    (如果还有小可爱没有看过我的顺序表,链表和栈的知识点说明,请看↓

    顺序表

    入门级别单链表

    带头双向循环链表(进阶版本)

    另外前两篇练习文章在下面,一定要把前一篇文章好好弄懂再看着一篇哦

    顺序表,链表和栈的练习

    练习题第二弹

    今天主要给大家分享链表的收尾习题 

    1.1合并两个有序链表

     

    其实很麻烦的这个题目,正常做的话因为是两个链表所以保存起来很复杂

    但是我们可以用哨兵位解决这个问题

    把每次比较的更小的节点拿下来放到哨兵位的后面

     

    在更改好指向之后tail别忘了后移一个指向节点1

    1. struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    2. struct ListNode*guard=(struct ListNode*)malloc(sizeof(struct ListNode));
    3. struct ListNode*tail=guard;
    4. tail->next=NULL;
    5. while(list1 && list2)
    6. {
    7. if(list1->val < list2->val )
    8. {
    9. tail->next=list1;
    10. list1=list1->next;
    11. tail=tail->next;
    12. }
    13. else
    14. {
    15. tail->next=list2;
    16. list2=list2->next;
    17. tail=tail->next;
    18. }
    19. }
    20. while(list1)
    21. {
    22. tail->next=list1;
    23. list1=list1->next;
    24. tail=tail->next;
    25. }
    26. while(list2)
    27. {
    28. tail->next=list2;
    29. list2=list2->next;
    30. tail=tail->next;
    31. }
    32. return guard->next;
    33. }

     


     1.2链表分割

    其实写完这个题感觉和上一个简直一模一样啊,只不过这次的题目链表只有一个,但是要创建两个新的哨兵位,一个保存比所给值x更小的节点,更一个保存>=的 

    最后返回更小链表哨兵位的下一个节点就可以了

    1. struct ListNode*guard1=(struct ListNode*)malloc(sizeof(struct ListNode)); //保存比x更小的
    2. struct ListNode*guard2=(struct ListNode*)malloc(sizeof(struct ListNode)); //保存比x更大
    3. struct ListNode*tail1=guard1;
    4. struct ListNode*tail2=guard2;
    5. tail1->next=NULL;
    6. tail2->next=NULL;
    7. while(pHead)
    8. {
    9. if(pHead->val //需要把节点放在guard1之后
    10. {
    11. tail1->next=pHead;
    12. pHead=pHead->next;
    13. tail1=tail1->next;
    14. }
    15. else
    16. {
    17. tail2->next=pHead;
    18. pHead=pHead->next;
    19. tail2=tail2->next;
    20. }
    21. }
    22. //把guard1的尾巴接到guard2上
    23. tail2->next=NULL;
    24. tail1->next=guard2->next;
    25. pHead=guard1->next;
    26. free(guard1);
    27. free(guard2);
    28. guard1=NULL;
    29. guard2=NULL;
    30. return pHead;
    31. }

     


    1.3链表的回文结构

     

     这哥对称结构很容易让人想到找到头指针,尾指针,都向中间走,但是你清醒一点,这是链表不是数组!!!!

    可以找到中间节点之后(这个在前面找中间节点的题写过了找中间节点

    找到之后反转一下吧

    比如123321 中间节点就是第二个3

    反转之后就是123    123

    如果不是回文结构12344569中间节点4

    反转之后1234  4569显然不一样

    所以代码 

    1. class PalindromeList {
    2. public:
    3. bool chkPalindrome(ListNode* A) {
    4. // write code here
    5. //找到中间节点
    6. struct ListNode *slow=A,*fast=A;
    7. while(fast&&fast->next)
    8. {
    9. fast=fast->next->next;
    10. slow=slow->next;
    11. }
    12. struct ListNode *cur=slow;
    13. struct ListNode *rhead=NULL;
    14. while(cur)
    15. {
    16. struct ListNode *next= cur->next;
    17. cur->next=rhead;
    18. rhead=cur;
    19. cur=next;
    20. }
    21. while(rhead)
    22. {
    23. if(rhead->val != A->val)
    24. {
    25. return false;
    26. }
    27. rhead=rhead->next;
    28. A=A->next;
    29. }
    30. return true;
    31. }
    32. };

    1.4判断两个链表是不是相交 

     

    这个题真的是坑啊

    首先我们来说一下常规思路

    肯定是先看一看相不相交,然后如果相交,让两个链表啊从同一个起始位置开始,往后遍历到有相同的节点!!!是相同的节点而不是节点的val相等!!!!!!!! 

    但是我们可以假设就是相交的啊,做到最后如果没有相等的节点就直接返回NULL就可以啊~~~

    其实思路不难直接上代码吧

    1. struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    2. struct ListNode *cur1=headA;
    3. struct ListNode *cur2=headB;
    4. int countA=0,countB=0;
    5. while(cur1)
    6. {
    7. ++countA;
    8. cur1=cur1->next;
    9. }
    10. while(cur2)
    11. {
    12. ++countB;
    13. cur2=cur2->next;
    14. }
    15. //此时的count就记录了两个链表的长度
    16. cur1=headA;
    17. cur2=headB;
    18. int gap=abs(countA-countB);
    19. if(countA//B链更长,应该B先走差距步,让俩个链表起始位置一样
    20. {
    21. while(gap--)
    22. {
    23. cur2=cur2->next;
    24. }
    25. }
    26. else
    27. {
    28. while(gap--)
    29. {
    30. cur1=cur1->next;
    31. }
    32. }
    33. //走到这两个链表就是一样长
    34. //假设两个链表相交那么走会在末尾之前找到一个节点,两个val一样
    35. while(cur1)
    36. {
    37. if(cur1 == cur2)
    38. {
    39. return cur2;
    40. }
    41. else{
    42. cur1=cur1->next;
    43. cur2=cur2->next;
    44. }
    45. }
    46. return NULL;
    47. }

     


    1.5判断是否有环 

     

     其实这个题难的根本就不是代码,只要还是之快慢指针的逻辑,快指针走两步,慢指针走一步,如果有环,那么快慢指针最终会相遇~~~否则永远不会相遇

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

    其实难的在于为什么快指针一定走两步,慢指针一定走一步才刚好合适?


    1.6返回入环点 

     

     有了刚才的铺垫这个简直太简单了

    区别就是在相遇之后记录一下相遇的位置,然后从相遇点和头分别往后走,第一次相遇的地方就是入环点

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


    1.7带随机指针的深度拷贝

     

    现在有了前面题目的铺垫这个也不算很难很难但是这个需要积累,方法就是把复制出来的节点像是跟班一样挂在原链表每一个节点后面,变成下面这样

    每次创建一个新节点然后改变一下指向

    最后再把复制的节点从原来的链表上拿下来

    1. struct Node* copyRandomList(struct Node* head) {
    2. struct Node*tmp=head;
    3. while(tmp)
    4. {
    5. struct Node*copy=(struct Node*)malloc(sizeof(struct Node));
    6. copy->val=tmp->val;
    7. copy->next=tmp->next;
    8. tmp->next=copy;
    9. tmp=copy->next;
    10. }
    11. tmp=head;
    12. while(tmp)
    13. {
    14. if(tmp->random == NULL)
    15. {
    16. tmp->next->random=NULL;
    17. }
    18. else
    19. {
    20. tmp->next->random=tmp->random->next;
    21. }
    22. tmp=tmp->next->next;
    23. }
    24. struct Node*copyTail=NULL,*copyHead=NULL;
    25. tmp=head;
    26. while(tmp)
    27. {
    28. struct Node*copy=tmp->next;
    29. struct Node*next=copy->next;
    30. if(copyTail==NULL)
    31. {
    32. copyHead=copyTail=copy;
    33. }
    34. else
    35. {
    36. copyTail->next=copy;
    37. copyTail=copy;
    38. }
    39. tmp->next=next;
    40. tmp=next;
    41. }
    42. return copyHead;
    43. }

     


    到此为止,我们顺序表和链表的所有练习就结束了,下一篇文章我们专注练习栈的知识~ 

     

     

  • 相关阅读:
    立体仓库货物识别率99.9%!AI让仓储管理事半功倍
    【计算机网络】网络层和数据链路层
    DHorse v1.4.0 发布,基于 k8s 的发布平台
    Python实现k-近邻算法案例学习
    Linux常用命令
    基于SSM框架的管理系统-计算机毕设 附源码 23402
    vue-grid-layout移动卡片到页面底部时页面滚动条跟随滚动
    【Spring注解必知必会】深度解析@Component注解实现原理
    Effective C++ 规则29:为“异常安全”而努力是值得的
    el-table中合并表头的同时,合并列固定(解决办法)+表头合并受fixed的影响合并不成功(解决办法)
  • 原文地址:https://blog.csdn.net/weixin_71138261/article/details/127823350