• LeetCode_21_简单_合并两个有序链表



    1. 题目

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

    示例 1:

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

    示例 2:

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

    示例 3:

    输入: l 1 = [ ] , l 2 = [ 0 ] l1 = [], l2 = [0] l1=[],l2=[0]
    输出: [ 0 ] [0] [0]


    提示

    • 两个链表的节点数目范围是 [ 0 , 50 ] [0, 50] [0,50]
    • 100 ≤ N o d e . v a l ≤ 100 100 \leq Node.val \leq 100 100Node.val100
    • l 1 l1 l1 l 2 l2 l2 均按 非递减顺序 排列

    2. 思路及代码实现(Python)

    2.1 递归

    可以通过递归的方式,不断地取出值较小的节点,并将该较小值节点指向后续链表和另一个链表得合并链表,不断地堆栈,直到到达边界条件,即最后一个节点指向 N o n e None None。用列表得形式直观地表示如下:

    { l i s t 1 [ 0 ] + m e r g e ( l i s t 1 [ 1 : ] , l i s t 2 ) l i s t 1 [ 0 ] < l i s t 2 [ 0 ] l i s t 2 [ 0 ] + m e r g e ( l i s t 1 , l i s t 2 [ 1 : ] ) o t h e r w i s e \left.\left\{

    list1[0]+merge(list1[1:],list2)list1[0]<list2[0]list2[0]+merge(list1,list2[1:])otherwise" role="presentation" style="position: relative;">list1[0]+merge(list1[1:],list2)list1[0]<list2[0]list2[0]+merge(list1,list2[1:])otherwise
    \right.\right. {list1[0]+merge(list1[1:],list2)list2[0]+merge(list1,list2[1:])list1[0]<list2[0]otherwise

    每次进行合并时,会取出两个链表地头节点,直到至少一个链表为空,在最差情况下,调用次数为两个链表长度之和 ( m + n ) (m+n) (m+n),即时间复杂度为 O ( m + n ) O(m+n) O(m+n),空间复杂度为为栈深,每调用一次栈深加一,因此空间复杂度也为 O ( m + n ) O(m+n) O(m+n)

    class Solution:
        def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
            if l1 is None:
                return l2
            elif l2 is None:
                return l1
            elif l1.val < l2.val:
                l1.next = self.mergeTwoLists(l1.next, l2)
                return l1
            else:
                l2.next = self.mergeTwoLists(l1, l2.next)
                return l2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    执行用时:43 ms
    消耗内存:16.43 MB

    2.2 迭代

    前面的方式是用递归的方式,把除了取出的头节点之外的链表的合并,归纳为一个合并函数,不断去调用直至边界条件,实现链表的合并。如果不把合并的操作定义为函数反复自调,那其实就是迭代的思路。

    这里我们可以设定一个哨兵节点 p r e h e a d prehead prehead ,该节点相当于另起一条链表,但最后返回结果的时候可以不包含该哨兵节点,该链表方便我们得到合并后的结果。通过维护一个 p r e v prev prev 指针,不断地调整该指针指向两个链表中值较小的头节点,不断迭代直至某个链表指向空节点,当 p r e v prev prev 指向某链表的头节点之后,该链表的头节点需更新为下一个节点。如果最后某链表为空,另外的链表还有剩余,则将剩余部分直接接到 p r e v prev prev 指针后面。

    同样的,迭代次数在最差情况下为 ( m + n ) (m+n) (m+n) 次,时间复杂度为 O ( m + n ) O(m+n) O(m+n),但由于我们只维护一个指针,此时的空间复杂度为 O ( 1 ) O(1) O(1)

    class Solution:
        def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
            prehead = ListNode(-1)
            prev = prehead
            while l1 and l2:
                if l1.val <= l2.val:
                    prev.next = l1
                    l1 = l1.next
                else:
                    prev.next = l2
                    l2 = l2.next            
                prev = prev.next
            prev.next = l1 if l1 is not None else l2
            return prehead.next
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    执行用时:34 ms
    消耗内存:16.38 MB

    题解来源:力扣官方题解

  • 相关阅读:
    RPA在财务预测和分析中的应用
    我眼中的大数据(一)
    WPF中加载GIF
    【Java】什么是API
    更换内存条需要注意什么
    FGSM(Fast Gradient Sign Method)算法源码解析
    Linux多线程控制:深入理解与应用(万字详解!)
    代码随想录算法训练营第六十二天 | 84.柱状图中最大的矩形
    计算机网络之概述
    Redis从基础到进阶篇(四)----性能调优、分布式锁与缓存问题
  • 原文地址:https://blog.csdn.net/Linshaodan520/article/details/136334142