21. 合并两个有序链表

迭代 + 虚拟头结点

解题思路

  1. 定义一个哨兵节点 dummy ,使用 dummy.next 来保存需要返回的头节点;

  2. 判断 l1l2 哪个更小,就把这个节点接到 dummy 下一个;

  3. 直到有一边为 null ,即可将另一边剩余的都接到 dummy 上;

复杂度

  1. 时间复杂度:O(n + m),其中 nm 分别为两个链表的长度;因为每次循环迭代中,l1l2 只有一个元素会被放进合并链表中, 因此 while 循环的次数不会超过两个链表的长度之和;所有其他操作的时间复杂度都是常数级别的,因此总的时间复杂度为 O(n+m)

  2. 空间复杂度:O(1)

代码实现

var mergeTwoLists = function (list1, list2) {
    let dmy = new ListNode(0, null);
    let curr = dmy;

    while (list1 && list2) {
        if (list1.val < list2.val) {
            curr.next = list1;
            list1 = list1.next;
        } else {
            curr.next = list2;
            list2 = list2.next;
        }
        curr = curr.next;
    }

    if (list1 === null) curr.next = list2;
    if (list2 === null) curr.next = list1;

    return dmy.next;
};

递归

解题思路

  1. 递归边界:如果其中一个链表为空,直接返回另一个链表作为合并后的结果;

  2. 如果两个链表都不为空,则比较两个链表当前节点的值,并选择较小的节点作为新链表的当前节点;例如 list1 的节点值更小,那么递归调用 mergeTwoLists(list1.next, list2),将递归返回的链表接在 list1 的末尾;

图解

复杂度

  1. 时间复杂度:O(n + m),其中 nm 分别为两个链表的长度;因为每次循环迭代中,l1l2 只有一个元素会被放进合并链表中, 因此 while 循环的次数不会超过两个链表的长度之和;所有其他操作的时间复杂度都是常数级别的,因此总的时间复杂度为 O(n+m)

  2. 空间复杂度:O(n + m),其中 n 和 m 分别为两个链表的长度;

代码实现:

var mergeTwoLists = function (list1, list2) {
    if (list1 === null) return list2;
    if (list2 === null) return list1;

    if (list1.val < list2.val) {
        list1.next = mergeTwoLists(list1.next, list2);
        return list1;
    }
    list2.next = mergeTwoLists(list1, list2.next);
    return list2;
};
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 迭代 + 虚拟头结点
    1. 1.1. 解题思路
    2. 1.2. 复杂度
    3. 1.3. 代码实现
  2. 2. 递归
    1. 2.1. 解题思路
    2. 2.2. 图解
    3. 2.3. 复杂度
    4. 2.4. 代码实现: