题解 | 【清晰图解】#合并两个排序的链表#递归和暴力解法

默认你已经理解题意了哈

题目意思

就是有两个链表,每个链表长度都是n,合并这两个链表成一个新链表,它的结点仍然是递增的,就是这个意思哈 alt

暴力如何解

思路我们可以用暴力来完成。当 l1l2 两个都不是空链表的时候,去判断 l1l2 哪一个链表的头节点的值更加的小,将较小值的节点添加到结果(肯定准备一个数组)里,当一个节点被添加到结果里之后,将对应链表中的节点向后移一位就行;

动图演示,请认真看仔细并理解我上面说的哈

alt

class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        // 使用带头结点的链表解决问题
        // 待输出链表的头部
        ListNode head = new ListNode();

        // 待输出链表的 last 结点
        ListNode last = head;
        while(l1 != null && l2 != null) {
            if(l1.val > l2.val) {
                last.next = l2;
                l2 = l2.next;
            }else{
                last.next = l1;
                l1 = l1.next;
            }
            last = last.next;
        }

        // l1 或 l2 可能还有剩余结点没有合并, 
        // 由于从上面的 while 循环中退出, 那么链表 l1 和 l2 至少有一个已经遍历结束
        if(l1 != null) last.next = l1;
        if(l2 != null) last.next = l2;

        return head.next;

    }
}

这里为了简单方便的处理, 给新链表先“安装”一个头结点比如head

  • 1 将 l2 链表的 1 结点摘下来,放到新链表的尾部。
  • 2 将 l2 链表的 2 结点摘下来,然后放到新链表的尾部。
  • 3 将 l1 链表的 3 结点摘下来,然后放到新链表的尾部。 同理...
  • l2 链表被摘完了, l2 == null

最后 l2 链表被“摘”完, l1 链表剩下的部分,“安装”在新链表的尾部。

复杂度分析下

时间复杂度

l1 和 l2 链表都遍历了一遍,那么时间复杂度是 O(n + m) n 和 m 是链表 l1 和 l2 的长度

空间复杂度

只多申请了一个链表头结点, 属于常数级别的, 那么空间复杂度 O(1)

递归如何解

终止条件:当两个链表都为空时,表示我们对链表已合并完成。 如何递归:我们判断 l1 和 l2 头结点哪个更小,然后较小结点的 next 指针指向其余结点的合并结果。

动图演示,请认真看仔细并理解我上面说的哈

alt

然后考虑递归的终止条件是当 l1==null返回 l2,还是l2==null返回l1, 然后就是判断l1的值是不是小于l2的值呢,如果确实小于递归调l1.next(就是l1的下一个结点),然后还是l2进行合并返回l1就行;反之也是我就不重复了也是一样的形式


class Solution {
 		public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
         		if(l1 == null) {
                   return l2; 
                }
          		else if (l2 == null) {
                   return l1;	  
                }
          		else if(l1.val < l2.val) {
                   l1.next = mergeTwoList(l1.next, l2);
                   return l1;
                }
          		else {
                   l2.next = mergeTwoLists(l1, l2.next);
                   return l2;
                }
          
        }
}

复杂度分析下

那怎么去算递归的时间复杂度和空间复杂度呢?

比如说给一个递归算法,它的时间复杂度是O(T),那么通常是递归调用的数量(记作 R)和算的时间复杂度的乘积(表示为 O(s))的乘积来表示:O(T)=R∗O(s)

你看哈,m,n为l1和l2的元素个数。递归每次掉一次在两个递增链表里面只去掉一个元素,直到两个链表都为空,那需要调R=(m+n)次,但是递归函数中调用次数操作中我们只进行了 next指针的赋值操作,它的复杂度就是O(1),故递归的总时间复杂度为O(T)=R∗O(1)=O(m+n)

我们在来看下空间复杂度,对于递归调用self.mergeTwoLists()(这个翻译过来:自己调自己),当这个递归调用遇到终止条件准备回溯时,其实已经递归调用了 m+nm+n 次,那么它就使用了 m+nm+n 个栈帧,故最后的空间复杂度还是O(m+n)

全部评论

相关推荐

10-15 09:13
已编辑
天津大学 soc前端设计
点赞 评论 收藏
分享
字节 飞书绩效团队 (n+2) * 15 + 1k * 12 + 1w
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务