• ⭐每天一道leetcode:21.合并两个有序链表(简单;双指针)


    ⭐今日份题目

    将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

    示例1

    输入:l1 = [1,2,4], l2 = [1,3,4]
    输出:[1,1,2,3,4,4]

    示例2

    输入:l1 = [], l2 = []
    输出:[]

    示例3

    输入:l1 = [], l2 = [0]
    输出:[0]

    提示

    • 两个链表的节点数目范围是 [0, 50]

    • -100 <= Node.val <= 100

    • l1l2 均按 非递减顺序 排列

    ⭐题目思路

    这里还是提取一下题目的特征点:

    • 合并

    • 链表

    • 升序

    该题目我的解题思路是双指针。我们先定义一个结果链表来存储结果,然后设置双指针:

    • 指针1指向链表1的开头,指针2指向链表2的开头;

    • 然后判断大小,小的一方加入到结果链表中,并且后移;

    • 直至遍历完两个链表中的所有节点

    这道题目的不同之处在于,传给函数的就已经是链表的初始位置了,所以不需要额外设置指针,直接用list1和list2即可。

    此外需要注意的点是:

    • 每次后移时记得结果链表也要后移

    • 我们定义的新结果链表是有一个多余初始点的,所以我们返回的是结果链表的next

    • 由于最后结果链表会指向结果链表中的最后一个节点,所以在开始的时候需要再定义一个指针指向结果链表的开头才能返回正确的结果

    该题目是链表相关的简单、经典题目,初学的同学们可以多看几遍,多做几次。

    ⭐链表合并补充知识

    信息检索课程中会涉及到bool检索模型,该模型中有and、or、and not、not等操作,这些操作是对postings的操作,postings是记录哪些document中记载了该term的链表,且已经按从小到大排好序了。这些操作都和链表合并相关,区别如下:

    • and取的是两个链表的公共部分,所以是双指针从头遍历到某一链表结束即可,判断,小的一方的指针后移,相同大小的加入结果链表中;

    • or取的是两个链表的非重复部分,所以是双指针都要从头遍历到尾,判断,小的一方加入结果链表中并同时指针后移,相同大小的只随便选择一方加入结果链表中并指针后移即可;

    • not操作是针对某一链表来说的,与and not中的not类似,我们直接来看and not;

    • and not是取出在list1中同时不在list2中的节点,所以是双指针,其中list1的指针从头遍历到尾,判断,如果是list1的值小于list2的值,那么将list1的节点加入结果链表并指针后移;如果大于,那么list2的指针后移;如果相等,那么两个指针都后移

    这里如果没学过可能会有点绕,不懂的地方欢迎评论区留言⭐~

    ⭐代码

    1. /**
    2. * Definition for singly-linked list.
    3. * struct ListNode {
    4. * int val;
    5. * ListNode *next;
    6. * ListNode() : val(0), next(nullptr) {}
    7. * ListNode(int x) : val(x), next(nullptr) {}
    8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
    9. * };
    10. */
    11. class Solution
    12. {
    13. public:
    14. ListNode* mergeTwoLists(ListNode* list1, ListNode* list2)
    15. {
    16. ListNode* ans=new ListNode(0);
    17. ListNode* first=ans;
    18. while(list1!=NULL||list2!=NULL)
    19. {
    20. if(list1==NULL)//表示list1没有未遍历到的节点了
    21. {
    22. while(list2!=NULL)//表示list2还有未遍历到的节点
    23. {
    24. ans->next=list2;//加入结果链表
    25. list2=list2->next;//指针后移:才能读取到下一个节点的信息
    26. ans=ans->next;//指针后移:当前ans只有一个next,所以后移是为了避免最后发现ans只有一个next也就是覆盖的情况
    27. }
    28. }
    29. else if(list2==NULL)
    30. {
    31. while(list1!=NULL)
    32. {
    33. ans->next=list1;
    34. list1=list1->next;
    35. ans=ans->next;
    36. }
    37. }
    38. //前两段是剪枝,额外判断了某一链表为空,另一链表循环加入结果链表的情况
    39. else//该情况是说list1和list2都还有未遍历到的节点
    40. {
    41. if(list1->val<=list2->val)
    42. {
    43. ans->next=list1;
    44. ans=ans->next;
    45. list1=list1->next;
    46. }
    47. else
    48. {
    49. ans->next=list2;
    50. ans=ans->next;
    51. list2=list2->next;
    52. }
    53. }
    54. }
    55. return first->next;//注意:返回的一定是next
    56. }
    57. };

    提交结果

    我的代码的时间消耗和内存消耗还有待改进,欢迎大家提供更高效的代码,如果过后有更优化的思路我还会继续更新的,大家评论区见!

    点赞收藏不迷路⭐~

  • 相关阅读:
    JDBC 在性能测试中的应用
    大数据技术基础实验十一:Hive实验——Hive分区
    vue3 ts 导出PDF jsPDF
    华纳云:WordPress如何制作CMS栏目块
    2024蓝桥杯每日一题(BFS)
    Spring源码之六-onRefresh()方法
    2023-11-9
    vue常见问题汇总
    Java 多线程编程核心技术有哪些
    暑期第一周总结
  • 原文地址:https://blog.csdn.net/qq_63349644/article/details/136461312