• 链表高频笔试的OJ题


    文章目录

    一、合并两个有序链表

    解题代码

    二、反转链表

    解题代码

    三、分割链表

    解题代码 

    四、链表的回文结构

    解题代码

    五、链表相交

    解题代码

    六、环形链表

    解题代码

    七、复制带有随机指针的复制链表

    解题代码

    一、合并两个有序链表

    题目来源:牛客网。

    题目难度:简单。

    题目描述:输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。

    数据范围: 0 <= n <= 1000,-1000≤节点值≤1000,要求:空间复杂度 O(1),时间复杂度 O(n)。

      题解关键思路:

    1. 定义一个哨兵位,易方便操作;
    2. 定义一个尾节点,插入时时刻改变尾节点,方便书写代码;
    3. 比较数据大小,依次尾插即可;
    4. 当有一个链表提前比较插入结束,不要忘记把另一个链表剩下的元素连接起来。

    解题代码

    1. struct ListNode* Merge(struct ListNode* pHead1, struct ListNode* pHead2 )
    2. {
    3. if(pHead1==NULL)
    4. {
    5. return pHead2;
    6. }
    7. if(pHead2==NULL)
    8. {
    9. return pHead1;
    10. }
    11. struct ListNode* head,* tail;
    12. head=tail=(struct ListNode*)malloc(sizeof(struct ListNode));
    13. while(pHead1&&pHead2)
    14. {
    15. if(pHead1->valval)
    16. {
    17. tail->next=pHead1;
    18. tail=pHead1;
    19. pHead1=pHead1->next;
    20. }
    21. else
    22. {
    23. tail->next=pHead2;
    24. tail=pHead2;
    25. pHead2=pHead2->next;
    26. }
    27. }
    28. if(pHead1)
    29. {
    30. tail->next=pHead1;
    31. }
    32. if(pHead2)
    33. {
    34. tail->next=pHead2;
    35. }
    36. struct ListNode* plist=head->next;
    37. free(head);
    38. return plist;
    39. }

    二、反转链表

    题目来源:牛客网。

    题目难度:简单。

    题目描述:给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。

    数据范围: 0≤n≤1000

    要求:空间复杂度 O(1) ,时间复杂度O(n) 。

      题解关键思路:

    1. 反转next的指向即可;
    2. 定义三个节点,分别指向空、首节点、第二个节点,从首节点开始反转,依次向后访问。
    3. 也可考虑头插的思路,即定义一个新节点为空,把题目中的链表依次头插入新节点即可。 

    解题代码

    1. // struct ListNode* ReverseList(struct ListNode* pHead ) {
    2. // if (pHead == NULL)
    3. // return NULL;
    4. // struct ListNode* n1, *n2, *n3;
    5. // n1 = NULL;
    6. // n2 = pHead;
    7. // n3 = pHead->next;
    8. // while (n2) {
    9. // n2->next = n1;
    10. // n1 = n2;
    11. // n2 = n3;
    12. // if (n3)
    13. // n3 = n3->next;
    14. // }
    15. // return n1;
    16. // }
    17. struct ListNode* ReverseList(struct ListNode* pHead )
    18. {
    19. if(pHead==NULL)
    20. return NULL;
    21. struct ListNode* newhead=NULL;
    22. struct ListNode* cur=pHead;
    23. struct ListNode* next=cur->next;
    24. while(cur)
    25. {
    26. cur->next=newhead;
    27. newhead=cur;
    28. cur=next;
    29. next=cur->next;
    30. }
    31. return newhead;
    32. }

    三、分割链表

    题目来源:LeetCode。

    题目难度:中等。

    题目描述:给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

    题解关键思路:

    1. 定义两个新节点,把大于x的和小于x的分成两部分;
    2. 最后连接两部分;
    3. 注意,最后应该将最后一个节点的next置空,防止成回链。

    解题代码 

    1. struct ListNode* partition(struct ListNode* head, int x)
    2. {
    3. struct ListNode* lesshead,*lesstail;
    4. lesshead=lesstail=(struct ListNode*) malloc(sizeof(struct ListNode));
    5. lesstail->next=NULL;
    6. struct ListNode* greaterhead,*greatertail;
    7. greaterhead=greatertail=(struct ListNode*)malloc(sizeof(struct ListNode));
    8. greatertail->next=NULL;
    9. struct ListNode* cur=head;
    10. while(cur)
    11. {
    12. if(cur->val
    13. {
    14. lesstail->next=cur;
    15. lesstail=cur;
    16. }
    17. else
    18. {
    19. greatertail->next=cur;
    20. greatertail=cur;
    21. }
    22. cur=cur->next;
    23. }
    24. lesstail->next=greaterhead->next;
    25. greatertail->next=NULL;
    26. struct ListNode* plist=lesshead->next;
    27. free(lesshead);
    28. free(greaterhead);
    29. return plist;
    30. }

    四、链表的回文结构

    题目来源:LeetCode。

    题目难度:简单。

    题目描述:给定一个链表的 头节点 head ,请判断其是否为回文链表。如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。

    题解关键思路:

    1. 第一步:找到前半部分尾结点(快慢指针);
    2. 第二步:翻转后半部分(翻转链表);
    3. 第三步:判断是否是回文链表(判断前后两部分的节点是否一致);
    4. 第四步:返回结果。

    解题代码

    1. struct ListNode* Reverse(struct ListNode* head)
    2. {
    3. struct ListNode* head1=head;
    4. struct ListNode *n1,*n2,*n3;
    5. n1=NULL;
    6. n2=head1;
    7. n3=head1->next;
    8. while(n2)
    9. {
    10. n2->next=n1;
    11. n1=n2;
    12. n2=n3;
    13. if(n3)
    14. n3=n3->next;
    15. }
    16. return n1;
    17. }
    18. bool isPalindrome(struct ListNode* head)
    19. {
    20. if(head==NULL||head->next==NULL)
    21. {
    22. return true;
    23. }
    24. struct ListNode* slow,*fast;
    25. slow=fast=head;
    26. while(fast&&fast->next)
    27. {
    28. slow=slow->next;
    29. fast=fast->next->next;
    30. }
    31. struct ListNode*headRev=Reverse(slow);
    32. struct ListNode*headBef=head;
    33. while(headBef&&headRev)
    34. {
    35. if(headBef->val!=headRev->val)
    36. {
    37. return false;
    38. }
    39. else
    40. {
    41. headBef=headBef->next;
    42. headRev=headRev->next;
    43. }
    44. }
    45. return true;
    46. }

    五、链表相交

    题目来源:LeetCode。

    题目难度:简单。

    题目描述:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

    题解关键思路:

    1.  指针 curA 指向 A 链表,指针 curB 指向 B 链表,依次往后遍历;
    2.  先判断curA 和curB的尾是否相同,如果相同,则交叉,如果不同,则不交叉;

    3. 统计两个链表的节点数来判断谁长谁短;

    4. 从头遍历,比较长的链表指针先走两者之差,长度差就消除了如此,再依次同时往后遍历找相同即可。

    解题代码

    1. struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
    2. {
    3. struct ListNode* curA=headA;
    4. struct ListNode* curB=headB;
    5. int countA=1;
    6. int countB=1;
    7. while(curA->next||curB->next)
    8. {
    9. if(curA->next)
    10. {
    11. curA=curA->next;
    12. countA++;
    13. }
    14. if(curB->next)
    15. {
    16. curB=curB->next;
    17. countB++;
    18. }
    19. }
    20. if(curA!=curB)
    21. {
    22. return NULL;
    23. }
    24. int gap=abs(countA-countB);
    25. struct ListNode* longlist=headA;
    26. struct ListNode* shortlist=headB;
    27. if(countA
    28. {
    29. longlist=headB;
    30. shortlist=headA;
    31. }
    32. while(gap--)
    33. {
    34. longlist=longlist->next;
    35. }
    36. while(longlist!=shortlist)
    37. {
    38. longlist=longlist->next;
    39. shortlist=shortlist->next;
    40. }
    41. return longlist;
    42. }

    六、环形链表

    题目来源:LeetCode。

    题目难度:中等。

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

      

    题解关键思路:

    1. 先判断是否为环形链表(快慢指针);
    2. 是环形链表后,找入环点;
    3. 找入环点的方法:一个指针从相遇点开始,另个一指针从头开始,当两个指针相等时即为入环点。 

    解题代码

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

    七、复制带有随机指针的链表

    题目来源:LeetCode。

    题目难度:中等。

    题目描述:给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。构造这个链表的 深拷贝。 深拷贝应该正好由n个全新节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 

    例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。返回复制链表的头节点

      

    题解关键思路:

    1. 首先我们可以忽略 random 指针,然后对原链表的每个节点进行复制,并追加到原节点的后面,而后复制 random 指针。

    2. 最后我们把原链表和复制链表拆分出来,并将原链表复原即可。

    解题代码

    1. struct Node* copyRandomList(struct Node* head)
    2. {
    3. struct Node* cur=head;
    4. //插入相同的节点
    5. while(cur)
    6. {
    7. struct Node* newnode=(struct Node*)malloc(sizeof(struct Node));
    8. newnode->val=cur->val;
    9. //插入节点
    10. newnode->next=cur->next;
    11. cur->next=newnode;
    12. cur=newnode->next;
    13. }
    14. //复制随机指针
    15. cur=head;
    16. while(cur)
    17. {
    18. if(cur->random==NULL)
    19. {
    20. cur->next->random=NULL;
    21. }
    22. else
    23. {
    24. cur->next->random=cur->random->next;
    25. }
    26. cur=cur->next->next;
    27. }
    28. //拆解插入的指针
    29. cur=head;
    30. struct Node* newhead=NULL,*newtail=NULL;
    31. while(cur)
    32. {
    33. struct Node*copy=cur->next;
    34. struct Node*next=copy->next;
    35. if(newtail==NULL)
    36. {
    37. newhead=newtail=copy;
    38. }
    39. else
    40. {
    41. newtail->next=copy;
    42. newtail=copy;
    43. }
    44. cur->next=next;
    45. cur=next;
    46. }
    47. return newhead;
    48. }

      链表的常见OJ题我们先例举到这里,后续我们会持续更新的哦ovo~

      感谢观看,希望本篇文章会对您有所帮助。

  • 相关阅读:
    javaScript 错误处理与调试
    JAVA小游戏 “拼图”
    药物研发检测记录模板-0903不溶性微粒检查法检验原始记录
    30 秒使用 Sealos 搭建个人密码管理器 Vaultwarden
    java毕业设计个人博客网站Mybatis+系统+数据库+调试部署
    【javaEE】网络初识
    虚拟机中安装和初始化linux(Cent OS7)操作系统
    制造行业数字化运维破局之道
    含文档+PPT+源码等]精品基于springboot+mybatis的在线基金管理平台vue[包运行成功]
    【51单片机实验笔记】声学篇(一) 蜂鸣器基本控制
  • 原文地址:https://blog.csdn.net/weixin_67596609/article/details/128104067