合并两个有序链表
描述
将两个已按升序排列的链表合并为一个新的升序链表,并返回该链表。
示例:
输⼊:1->3->5, 2->4->6
输出:1->2->3->4->5->6
前置知识
- 递归
- 链表
思路
使⽤递归的方式来实现,将两个链表头部较⼩的⼀个与剩下的元素合并,并返回排好序的链表
头,当两条链表中的⼀条为空时终⽌递归。
关键点
- 掌握链表数据结构
- 考虑边界情况
代码
javascript">const mergeTwoLists = function (l1, l2) {
if (l1 === null) {
return l2;
}
if (l2 === null) {
return l1;
}
if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
解释
1、基础情况:
如果l1是null(即空链表),那么函数直接返回l2。因为没有什么可以与空链表合并,所以结果就是另一个链表。
同样,如果l2是null,函数返回l1。
2、递归情况:
比较l1和l2当前节点的值(l1.val和l2.val)。
- 如果l1.val小于l2.val,那么l1的当前节点应该在新合并链表的当前位置。为了完成合并,我们需要递归地合并l1的剩余部分(即l1.next)和l2。这通过调用mergeTwoLists(l1.next, l2)实现,并将返回的链表设置为l1.next。最后,返回l1,因为现在l1是新合并链表的头节点。
- 如果l2.val小于或等于l1.val,那么l2的当前节点应该在新合并链表的当前位置。同样地,我们需要递归地合并l1和l2的剩余部分(即l2.next)。这通过调用mergeTwoLists(l1, l2.next)实现,并将返回的链表设置为l2.next。最后,返回l2,因为现在l2是新合并链表的头节点。
- 这个递归过程会一直进行,直到达到基础情况之一(即一个链表为空)。在这一点上,递归开始“解开”,将每个步骤中确定的节点链接起来,形成最终合并的链表
复杂度分析
M、N 是两条链表 l1、l2 的⻓度
时间复杂度:O(M + N),每个节点都只被访问一次,并且每次递归调用都会处理一个节点
空间复杂度:O(M + N),在最坏的情况下(当链表完全不平衡时),因为递归调用栈的深度可能达到M + N
扩展
使⽤迭代的⽅式,代码如下:
javascript">function mergeTwoLists (l1, l2) {
constprehead = new ListNode(-1);
let 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;
}
prev.next = l1 === null ? l2 : l1;
return prehead.next;
}