• 链表oj (7.29)


     203. 移除链表元素 - 力扣(LeetCode)

    思路1:使用结构体指针 cur 遍历链表,遇到值为 val 时删除,删除之前需要判断是头删还是正常的删除,头删需要改变头指针;

    正常的删除需要 cur(待删除节点)和 cur 前面一个节点 prev ,让prev 指向 cur 的下一个节点,然后释放掉 cur节点,再让 cur 指针指向现在 prev 指向的下一个节点(原来 cur 指向的下一个节点)。

    那么如何找到 prev ?每一次遍历结束先将 cur 赋给 prev,cur 再往后移动一个节点,这样下一次遍历时,prev 就是 cur 的上一个节点。

    问题:修改头指针不应该传头指针的地址(二级指针)吗?为什么这里没有?

    因为函数结束返回新的头节点,因此本题中可以不传二级指针(通常不推荐)。

    实现:

    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * struct ListNode *next;
    6. * };
    7. */
    8. struct ListNode* removeElements(struct ListNode* head, int val)
    9. {
    10. struct ListNode* prev=NULL;
    11. struct ListNode* cur=head;
    12. while(cur)
    13. {
    14. //遇到val,需要删除
    15. if(cur->val==val)
    16. {
    17. //判断是否为头删
    18. if(cur==head)
    19. {
    20. //头指针指向第二个节点
    21. head=cur->next;
    22. //释放第一个节点
    23. free(cur);
    24. //第二个节点成为头节点
    25. cur=head;
    26. }
    27. //正常删除
    28. else
    29. {
    30. //cur的上一个节点指向指向cur的下一个节点
    31. prev->next=cur->next;
    32. //释放掉cur节点
    33. free(cur);
    34. //cur指针指向原来cur的下一个节点
    35. cur=prev->next;
    36. }
    37. }
    38. else
    39. {
    40. //记录当前cur为上一个节点prev
    41. prev=cur;
    42. //cur向下一个节点移动
    43. cur=cur->next;
    44. }
    45. }
    46. return head;
    47. }

    思路2:

    定义一个 cur 指针遍历原链表,把不是 val 的节点,尾插到头节点为 newhead 的新链表,是 val 的节点,就释放掉。

    释放的过程为先定义一个 del 节点来记录待删除的节点,然后 cur 往后移,释放 del 节点。

    这样的做法势必导致时间复杂度的增加,因为每次尾插都要查找尾节点,如何解决呢?

    定义一个尾指针 tail 来记录尾节点,cur 完成遍历后不能忘了将 tail 指向空,还需要考虑到如果原链表为空,那么 newhead 就为空,tail 也为空,因此需要限制 tail 不为空的时候才能将其指向空。

    实现:

    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * struct ListNode *next;
    6. * };
    7. */
    8. struct ListNode* removeElements(struct ListNode* head, int val)
    9. {
    10. struct ListNode* cur=head;
    11. struct ListNode* newhead=NULL,*tail=NULL;
    12. while(cur)
    13. {
    14. //删除
    15. if(cur->val==val)
    16. {
    17. struct ListNode* del=cur;
    18. cur=cur->next;
    19. free(del);
    20. }
    21. else
    22. {
    23. //尾插(头插)
    24. if(tail==NULL)
    25. {
    26. //头节点等于尾节点
    27. newhead=tail=cur;
    28. }
    29. else
    30. //正常尾插
    31. {
    32. //尾节点指向插入的节点
    33. tail->next=cur;
    34. //尾节点向后移动
    35. tail=tail->next;
    36. }
    37. //遍历节点后移
    38. cur=cur->next;
    39. }
    40. }
    41. //遍历完成后,将尾节点指向空
    42. if(tail)
    43. {
    44. tail->next=NULL;
    45. }
    46. return newhead;
    47. }

     

    876. 链表的中间结点 - 力扣(LeetCode)

    法1:先遍历一遍找出链表的长度,再遍历一遍找出中间节点。

    但如果要求只能遍历一遍呢?

    法2:这时就可以定义两个指针,一个走得慢,另一个走得快,速度是慢指针的两倍,

    在链表有偶数个节点的情况下,快指针走到尾节点(下一个节点为空)的时候,慢指针刚好走到链表中间节点。

    在链表为奇数个节点的情况下,当快指针走到尾节点后面一个位置(空)的时候,慢指针恰好处于链表的第二个中间节点。

    无论是奇数个还是偶数个节点,直接返回慢节点,就能得到我们需要的结果。

    实现:

    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * struct ListNode *next;
    6. * };
    7. */
    8. struct ListNode* middleNode(struct ListNode* head){
    9. struct ListNode* slow=head,*fast=head;
    10. while(fast&&fast->next)
    11. {
    12. slow=slow->next;
    13. fast=fast->next->next;
    14. }
    15. return slow;
    16. }

     

    链表中倒数第k个结点_牛客题霸_牛客网 (nowcoder.com)

    本题同样采用和上题类似的快慢指针的做法,使用了 相对距离 的原理。

    先让快指针向前移动 k 个节点,这样快慢指针之间的距离就为 k 个节点;

    我们的目的是找出倒数第 k 个节点,当快指针走到 NULL 的时候,慢指针就刚好走到倒数第 k 个节点的位置上了。

    我们还需要考虑到如果链表为空或者 k <=0的情况,直接返回NULL;如果 k 大于链表的长度,也要返回空。

    实现:

    1. /**
    2. * struct ListNode {
    3. * int val;
    4. * struct ListNode *next;
    5. * };
    6. */
    7. /**
    8. *
    9. * @param pListHead ListNode类
    10. * @param k int整型
    11. * @return ListNode类
    12. */
    13. struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    14. if(!pListHead||k<=0)
    15. {
    16. return NULL;
    17. }
    18. struct ListNode* slow=pListHead,*fast=pListHead;
    19. while(k--)
    20. {
    21. if(fast)
    22. {
    23. fast=fast->next;
    24. }
    25. else {
    26. return NULL;
    27. }
    28. }
    29. while(fast)
    30. {
    31. slow=slow->next;
    32. fast=fast->next;
    33. }
    34. return slow;
    35. }

    21. 合并两个有序链表 - 力扣(LeetCode)

    创建一个新的空链表,并记录它的头节点和尾节点;

    比较两个链表相同位置节点的大小,较小的一方就头插到新链表中,直到有两个链表中的其中一个先走到了空,结束插入,将有剩余的链表链接到新链表。

    需要注意如果开始就有一条链表为空,那么直接返回另外一条链表。

    实现:

    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * struct ListNode *next;
    6. * };
    7. */
    8. struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    9. if(list1==NULL)
    10. {
    11. return list2;
    12. }
    13. if(list2==NULL)
    14. {
    15. return list1;
    16. }
    17. struct ListNode* phead=NULL,*tail=NULL;
    18. while(list1&&list2)
    19. {
    20. if(list1->valval)
    21. {
    22. if(tail==NULL)
    23. {
    24. phead=tail=list1;
    25. }
    26. else
    27. {
    28. tail->next=list1;
    29. tail=tail->next;
    30. }
    31. list1=list1->next;
    32. }
    33. else
    34. {
    35. if(tail==NULL)
    36. {
    37. phead=tail=list2;
    38. }
    39. else
    40. {
    41. tail->next=list2;
    42. tail=tail->next;
    43. }
    44. list2=list2->next;
    45. }
    46. }
    47. if(list1==NULL)
    48. {
    49. tail->next=list2;
    50. }
    51. if(list2==NULL)
    52. {
    53. tail->next=list1;
    54. }
    55. return phead;
    56. }
  • 相关阅读:
    深入Java了解面向对象编程(OOP)
    stata17中java installation not found或java not recognozed的问题
    iNFTnews | “幻核”停售数字藏品,腾讯元宇宙又将如何发展?
    二十、处理器调度(RR时间片轮转,MLFQ多级反馈队列,CFS完全公平调度器,优先级翻转;多处理器调度)
    【Kubernetes系列】工作负载资源之Deployment
    vue setup:Options API 迁移至 Composition API 的一些语法要点
    Hutool 实现敏感信息展示脱敏及其反脱敏
    Django channel 解析
    基于51单片机水位监测控制报警仿真设计( proteus仿真+程序+设计报告+讲解视频)
    【web-攻击用户】(9.1.6)查找并利用XSS漏洞--基于DOM
  • 原文地址:https://blog.csdn.net/dn235z/article/details/133774475