Loading

合并两个有序链表

1.问题描述

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

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

2.求解

迭代

  1. 设置哑节点dummy,便于我们返回链表
  2. 当l1和l2非空时,遍历l1、l2链表,比较他们的值,将dummy的next指向值较小的节点,并将较小值节点指向下一个节点
  3. 当遍历完成时,判断l1、l2是否仍然非空,将dummy指向非空节点
代码如下
/*
执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
内存消耗:38.3 MB, 在所有 Java 提交中击败了89.31% 的用户
*/
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    ListNode l3 = new ListNode(0);
    ListNode dummy = l3;
    while (l1 != null && l2 != null) {
        if (l1.val < l2.val) {
            l3.next = l1;
            l1 = l1.next;
        } else {
            l3.next = l2;
            l2 = l2.next;
        }
        l3 = l3.next;
    }
    if (l1 != null) {
        l3.next = l1;
    } else {
        l3.next = l2;
    }
    return dummy.next;
}
  • 时间复杂度O(m + n),m、n分别是两个链表长度,至多每个节点都会调用一次
  • 空间复杂度O(1),只使用了常数级的空间

递归

  • 递:每次深入是值较小的节点
  • 归:当遇到一个节点为null时,开始返回
代码如下
/*
执行用时:0 ms, 在所有 Java 提交中击败了100.00% 的用户
内存消耗:38.4 MB, 在所有 Java 提交中击败了76.99% 的用户
*/
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    return access(l1, l2);
}

public ListNode access(ListNode l1, ListNode l2) {
    if (l1 == null) {
        return l2;
    }
    if (l2 == null) {
        return l1;
    }
    if (l1.val < l2.val) {
        l1.next = access(l1.next, l2);
        return l1;
    } else {
        l2.next = access(l1, l2.next);
        return l2;
    }
}
  • 时间复杂度O(m + n),m、n分别是两个链表长度,至多每个节点都会调用一次
  • 空间复杂度O(m + n),每次调用方法都会消耗栈空间,栈空间的大小取决于递归的深度,最多递归m + n次

ps:递归的空间复杂度不一定都是调用方法的次数,若函数在尾位置调用自身(或是一个尾调用本身的其他函数等等),则称这种情况就是尾递归。java语言对尾递归进行了优化,尾递归占用的栈空间是常数级的(能优化成尾递归说明可以写成迭代)

尾递归的优化

posted @ 2020-10-08 15:11  水纸杯  阅读(165)  评论(0)    收藏  举报