题目描述
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列
思考一:迭代
通过引入哨兵节点(guard)简化头节点处理,使用双指针分别遍历两个有序链表,每次将值较小的当前节点连接到结果链表尾部,直至其中一个链表遍历完毕,最后拼接剩余节点,最终返回哨兵节点的后继节点即为合并后的有序链表。
算法过程
- 初始化:创建哨兵节点guard(用于简化头节点处理),定义指针p1、p2分别指向两个输入链表的头节点,指针p指向guard(用于构建结果链表)。
- 边界处理:若任一链表为空,直接返回另一链表(无需合并)。
- 遍历合并:当p1和p2均未遍历完时,循环执行:
- 比较p1.val与p2.val,将值较小的节点连接到p.next。
- 移动被选中节点的指针(p1或p2)及结果指针p。
- 拼接剩余节点:当其中一个链表遍历完后,将另一个链表的剩余部分直接连接到p.next。
- 返回结果:返回guard.next(哨兵节点的后继节点即为合并后链表的头节点)。
该算法时间复杂度为O(n+m)(n、m为两链表长度),空间复杂度为O(1)(仅使用常数级额外空间)。
代码
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} list1
* @param {ListNode} list2
* @return {ListNode}
*/
var mergeTwoLists = function(list1, list2) {
let p1 = list1;
let p2 = list2;
if (!p1 || !p2) {
return p1 ? p1 : p2;
}
let guard = new ListNode();
let p = guard;
while (p1 || p2) {
if (!p1) {
p.next = p2;
break;
}
if (!p2) {
p.next = p1;
break;
}
if (p1.val < p2.val) {
p.next = p1;
p1 = p1.next;
} else {
p.next = p2;
p2 = p2.next;
}
p = p.next;
}
return guard.next;
};
思考二:递归
递归解法的核心是将"合并两个有序链表"的问题分解为更小的同类子问题:
- 若其中一个链表为空,直接返回另一个链表(递归终止条件)
- 否则比较两个链表当前头节点的值,选择值较小的节点作为合并后链表的头节点
- 被选中节点的next指针应指向"该节点的next部分与另一个链表"合并后的结果(递归调用)
- 最终返回选中的头节点,形成完整的合并链表
这种思路利用递归的自相似性,将原问题逐步简化,直到触及终止条件,再层层返回结果构建最终链表。
算法过程
-
终止条件判断:
- 若list1为空,返回list2
- 若list2为空,返回list1
-
节点选择与递归:
- 若list1.val < list2.val:
- 递归合并list1.next与list2,得到子结果
- 将list1.next指向该子结果
- 返回list1作为当前合并段的头节点
- 否则:
- 递归合并list1与list2.next,得到子结果
- 将list2.next指向该子结果
- 返回list2作为当前合并段的头节点
- 若list1.val < list2.val:
-
结果构建:通过递归调用的返回值,自动完成链表节点的正确连接,最终形成完整的有序链表
该算法的时间复杂度为O(n+m)(n和m分别为两个链表的长度),空间复杂度为O(n+m)(递归调用栈的深度)。
代码
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} list1
* @param {ListNode} list2
* @return {ListNode}
*/
var mergeTwoLists = function(list1, list2) {
let p1 = list1;
let p2 = list2;
if (!p1 || !p2) {
return p1 ? p1 : p2;
}
let p3 = null;
if (p1.val < p2.val) {
p3 = mergeTwoLists(p1.next, p2);
p1.next = p3;
return p1;
} else {
p3 = mergeTwoLists(p1, p2.next);
p2.next = p3;
return p2;
}
};
412

被折叠的 条评论
为什么被折叠?



