LeetCode 21 合并两个有序链表

138 阅读2分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」。

题目:给定两个有序链表,要求将两个有序链表进行合并,输出合并后的链表(保持有序)。

解题思路

本题的简单思路很容易想到,因为两个链表都是有序的,此时我们可以使用双指针法来解决问题,具体思路为:首先设置一个头节点,用来保存最终的合并链表,之后为了减少内存使用,此处将原链表的头结点作为两个待移动指针,通过循环来遍历两个链表,每次遍历判断两个链表指针指向的值的大小,哪个小则设置头节点的next为此节点,之后此节点后移,头节点也后移,直到两个链表存在一个链表为空时,停止循环。之后判断哪个链表为空,将头节点的next指向不为空的链表即可,代码如下:

public static ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode head = new ListNode(0);
        ListNode cur = head;
        while(list1!=null && list2!=null){
            if(list1.val<list2.val){
                cur.next = list1;
                list1 = list1.next;
            }else {
                cur.next = list2;
                list2 = list2.next;
            }
            cur = cur.next;
        }
        cur.next = list1==null?list2:list1;
        return head.next;
    }

该算法的时间复杂度为O(m+n)O(m+n),其中m,n分别表示两个链表的长度,空间复杂度为O(1)O(1)

进阶解法 递归

递归的思路很巧妙,使用递归,此处必须引入递归的两个条件,第一个是终止条件,第二个是函数的执行体(函数干了什么)。根据本题,如果使用递归解决问题,那么终止条件即为两个链表其中一个链表为空则返回另一个链表,函数体则是判断两个链表的第一个元素的大小,哪个链表元素小则设置哪个链表的next指针指向下一层递归函数,直到递归结束。实际上,此递归可以想象为每次拿出元素较小的结点,根据多次循环,链表结点离散化,之后递归结束是系统出栈将元素串起来了,代码如下:

 public static ListNode mergeTwoLists2(ListNode list1, ListNode list2){
        if(list1 == null) return list2;
        if(list2 == null) return list1;
        if(list1.val < list2.val){
             list1.next = mergeTwoLists2(list1.next, list2);
             return list1;
        }else {
             list2.next = mergeTwoLists2(list1, list2.next);
             return list2;
        }
    }

因为算法递归调用最多会调用合并后链表长度的次数,因此该算法的时间复杂度为O(m+n)O(m+n), 而每次调用的结果都存在系统栈空间中,因此空间复杂度为O(m+n)O(m+n)