LeetCode Merge Two Sorted Lists

来源:互联网 发布:英雄联盟官方代练 知乎 编辑:程序博客网 时间:2024/06/06 19:05

问题网址:https://leetcode.com/problems/merge-two-sorted-lists/description/

问题描述:
合并两个已排序的链接列表并将其作为新列表返回。 新列表应通过将前两个列表的节点拼接在一起来完成。

问题样例:

Input: 1->2->4, 1->3->4Output: 1->1->2->3->4->4

递归方法

我们可以递归地在两个列表上定义合并操作的结果,如下所示(避免围绕空列表的转角情况逻辑):

\ left {\ begin {array} {ll} list1 [0] + merge(list1 [1:],list2)&list1 [0]

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 = mergeTwoLists(l1.next, l2);            return l1;        }        else {            l2.next = mergeTwoLists(l1, l2.next);            return l2;        }    }}

复杂性分析
时间复杂度:O(n + m)
由于每次递归调用都会将指针递增为l1或l2(在每个列表末尾接近悬空的null),每个列表中每个元素只会有一次调用mergeTwoLists。 因此,列表的组合大小的时间复杂度是线性的。

空间复杂度:O(n + m)
第一次调用mergeTwoLists不会返回,直到l1和l2都结束,所以n + mn + m栈帧消耗O(n + m)空间。

迭代方法[接受]

通过假设l1完全小于l2并逐个处理元素,在l1中的必要位置插入l2的元素,我们可以通过迭代实现相同的想法。

首先,我们设置了一个虚假的“prehead”节点,以便我们稍后可以轻松地返回合并列表的头部。我们还维护一个prev指针,它指向我们正在考虑调整其下一个指针的当前节点。然后,我们做以下事情,直到l1和l2中的至少一个指向空:如果l1处的值小于或等于l2处的值,则将l1连接到前一个节点并且递增l1。否则,我们也是这样做,但对于l2。然后,无论我们连接了哪个列表,我们都会增加prev,使其跟我们的列表头之一保持一步。

循环结束后,l1和l2中至多有一个非空。因此(因为输入列表是按排序顺序排列的),如果任何一个列表都是非空的,它只包含大于所有先前合并的元素的元素。这意味着我们可以简单地将非空列表连接到合并列表并返回它。

class Solution {    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {        // maintain an unchanging reference to node ahead of the return node.        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;        }        // exactly one of l1 and l2 can be non-null at this point, so connect        // the non-null list to the end of the merged list.        prev.next = l1 == null ? l2 : l1;        return prehead.next;    }}

复杂性分析
时间复杂度:O(n + m)

因为在每个循环迭代中,l1和l2中的一个是递增的,所以while循环运行迭代次数等于两个列表的长度之和。 所有其他的工作是不变的,所以整体的复杂性是线性的。

空间复杂度:O(1)
迭代方法只分配几个指针,所以它的内存占用总是不变的。

原创粉丝点击