Leetcode No.21-合并两个有序链表(简单)——Java

难度:简单

将两个升序链表合并为一个新的升序链表并返回。
新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

方法一:(暴力法)

题目中要求,新链表是不能开辟额外的空间的,而是去拼接原来的两个链表的所有结点。

思路:
  • 这里的合并,就是从头结点开始比较 l 1 l1 l1 l 2 l2 l2 ,然后把较小的结点先加入最终要返回的链表之中。
  • 所以需要有一个临时指针,指向链表合并的当前结点。
  • 另外两个指针,分别指向原链表中正在被比较的两个结点
  • 引入哑结点(也可以说是哨兵结点),可以让我们更容易地返回合并后的链表
代码过程:
  • 我们维护一个 p r e v prev prev 指针 (最开始是指向哨兵结点的),我们需要做的是调整它的 n e x t next next 指针。
  • 然后,我们重复以下过程,直到 l 1 l1 l1或者 l 2 l2 l2 指向了 n u l l null null
    • 如果当前l1.val<=l2.val
      • l 1 l1 l1 当前的节点接在 p r e v prev prev 节点的后面
      • 同时将 l 1 l1 l1 指针往后移一位。
    • 否则
      • l 2 l2 l2 当前的节点接在 p r e v prev prev 节点的后面
      • 同时将 l 2 l2 l2 指针往后移一位。
    • 不管我们将哪一个元素接在了后面,都需要把 p r e v prev prev 向后移一位。
  • 在循环终止的时候, l 1 l1 l1 l 2 l2 l2 至多有一个是非空的。
  • 由于输入的两个链表都是有序的,所以不管哪个链表是非空的,它包含的所有元素都比前面已经合并链表中的所有元素都要大。
  • 我们只需要简单地将非空链表接在合并链表的后面,并返回合并链表即可。

在这里插入图片描述

代码:
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    	//构建哨兵结点
        ListNode prehead = new ListNode(-1);
		
        ListNode prev = prehead;
        while (l1 != null && l2 != null) {
            if (l1.val <= l2.val) {
                prev.next = l1;
                l1 = l1.next;
            } else {
                prev.next = l2;
                l2 = l2.next;
            }
            prev = prev.next;
        }

        // 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
        prev.next= (l1 == null) ? l2 : l1;

        return prehead.next;
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-by-leetcode-solu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复杂度分析:
  • 时间复杂度: O ( n + m ) O(n+m) O(n+m) ,其中 n n n m m m 分别为两个链表的长度。因为最坏的情况下,我们需要把两个链表都遍历一遍。时间复杂度和链表的长度在一个量级。
  • 空间复杂度: O ( 1 ) O(1) O(1) 。我们只需要常数的空间存放若干变量。

方法二:(递归)

思路:
  • 假设 l 1 l1 l1 的头结点的值较小,那么合并 l 1 l1 l1 l 2 l2 l2,等价于 l 1. n e x t l1.next l1.next 指向 l 1. n e x t l1.next l1.next l 2 l2 l2 合并的结果。其中合并 l 1. n e x t l1.next l1.next l 2 l2 l2 是原问题的一个子问题
  • 子问题和原问题具有相同结构,考虑自上而下的递归
代码:
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1==null)
            return l2;
         if(l2==null)
            return l1;
        
        ListNode head = null;

        if(l1.val<=l2.val){
            head = l1;
            head.next = mergeTwoLists(l1.next,l2);
        }else{
            head = l2;
            head.next = mergeTwoLists(l2.next,l1);
        }
        return head;
    }
}
复杂度分析:
  • 时间复杂度: O ( n + m ) O(n+m) O(n+m) ,因为每次调用递归都会去掉 l 1 l1 l1 或者 l 2 l2 l2 的头节点(直到至少有一个链表为空),函数 mergeTwoList 至多只会递归调用每个节点一次。因此,时间复杂度取决于合并后的链表长度,即 O ( n + m ) O(n+m) O(n+m)
  • 空间复杂度: O ( n + m ) O(n+m) O(n+m) 。其中 n n n m m m 分别为两个链表的长度。递归调用 mergeTwoLists 函数时需要消耗栈空间,栈空间的大小取决于递归调用的深度。结束递归调用时 mergeTwoLists 函数最多调用 n + m n+m n+m 次,因此空间复杂度为 O ( n + m ) O(n+m) O(n+m)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值